mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Compare commits
	
		
			105 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2eacae8f2e | ||
| 
						 | 
					403d5f1489 | ||
| 
						 | 
					f227633959 | ||
| 
						 | 
					83c8846728 | ||
| 
						 | 
					78ee99adcf | ||
| 
						 | 
					de4090d920 | ||
| 
						 | 
					732cadd2c8 | ||
| 
						 | 
					6747b60a95 | ||
| 
						 | 
					90ae9ed0a2 | ||
| 
						 | 
					206be49c69 | ||
| 
						 | 
					45559e9230 | ||
| 
						 | 
					f94b846224 | ||
| 
						 | 
					3ea3a69821 | ||
| 
						 | 
					46ddc65626 | ||
| 
						 | 
					71f313749e | ||
| 
						 | 
					80a5abbbe3 | ||
| 
						 | 
					ba812f7e86 | ||
| 
						 | 
					345c37a543 | ||
| 
						 | 
					b3457cd250 | ||
| 
						 | 
					fcf1864db3 | ||
| 
						 | 
					9221b67f3b | ||
| 
						 | 
					732d595a26 | ||
| 
						 | 
					3bc9d53628 | ||
| 
						 | 
					b5a4f45dbf | ||
| 
						 | 
					e6bafbf3e3 | ||
| 
						 | 
					5c7b128166 | ||
| 
						 | 
					5469edc278 | ||
| 
						 | 
					66952183a9 | ||
| 
						 | 
					cc97f58d96 | ||
| 
						 | 
					5d6931881a | ||
| 
						 | 
					0f4be7699b | ||
| 
						 | 
					546983cdbc | ||
| 
						 | 
					c04de4e7bb | ||
| 
						 | 
					d46cdd80de | ||
| 
						 | 
					6676e63c89 | ||
| 
						 | 
					1f99c3aaae | ||
| 
						 | 
					e6ef4e7484 | ||
| 
						 | 
					b0fa041a28 | ||
| 
						 | 
					e17bf77bdd | ||
| 
						 | 
					802b1fad61 | ||
| 
						 | 
					8a8973eec2 | ||
| 
						 | 
					17e7ea66e4 | ||
| 
						 | 
					9c3fad2c42 | ||
| 
						 | 
					227a800d26 | ||
| 
						 | 
					24cae67f3e | ||
| 
						 | 
					0d47c408ac | ||
| 
						 | 
					f1b557988d | ||
| 
						 | 
					95e504aa97 | ||
| 
						 | 
					a5ae091fdd | ||
| 
						 | 
					249f799a88 | ||
| 
						 | 
					dc395843ff | ||
| 
						 | 
					c5d003e09e | ||
| 
						 | 
					e6398d886b | ||
| 
						 | 
					23140d6f94 | ||
| 
						 | 
					36c823eef1 | ||
| 
						 | 
					fa393fa1e9 | ||
| 
						 | 
					e0fc37a437 | ||
| 
						 | 
					4aa2b0e35b | ||
| 
						 | 
					e01f6e7f33 | ||
| 
						 | 
					388b48d14e | ||
| 
						 | 
					352b967d1b | ||
| 
						 | 
					ed4da25f2f | ||
| 
						 | 
					5abda312ed | ||
| 
						 | 
					75862d3131 | ||
| 
						 | 
					8733542b13 | ||
| 
						 | 
					d7aac20cc1 | ||
| 
						 | 
					8b5361412c | ||
| 
						 | 
					3a971ba0d1 | ||
| 
						 | 
					c4b90354ca | ||
| 
						 | 
					28fd236044 | ||
| 
						 | 
					17b5701f19 | ||
| 
						 | 
					9bea6eb78c | ||
| 
						 | 
					fd57bd5f6f | ||
| 
						 | 
					d0dbda4106 | ||
| 
						 | 
					35a738214c | ||
| 
						 | 
					afbe872045 | ||
| 
						 | 
					909be19285 | ||
| 
						 | 
					8ee08c6b78 | ||
| 
						 | 
					c053e07336 | ||
| 
						 | 
					2b30cbdfa8 | ||
| 
						 | 
					c9df010416 | ||
| 
						 | 
					3a3e1b57c6 | ||
| 
						 | 
					186d4f1a0b | ||
| 
						 | 
					cc2f7937ed | ||
| 
						 | 
					960c031a67 | ||
| 
						 | 
					4993452561 | ||
| 
						 | 
					43eed63b09 | ||
| 
						 | 
					7a6d9c2f72 | ||
| 
						 | 
					f3715dc0d3 | ||
| 
						 | 
					a68a863b9d | ||
| 
						 | 
					18717f5247 | ||
| 
						 | 
					677b5396cb | ||
| 
						 | 
					5d0e07112f | ||
| 
						 | 
					a5acaa68db | ||
| 
						 | 
					7787a3aeae | ||
| 
						 | 
					dd1ddf74fc | ||
| 
						 | 
					5e101c9fed | ||
| 
						 | 
					f6db465082 | ||
| 
						 | 
					a7e6fbc220 | ||
| 
						 | 
					cd132126ef | ||
| 
						 | 
					249d21eb1e | ||
| 
						 | 
					0127a0608d | ||
| 
						 | 
					8b663e4d7c | ||
| 
						 | 
					5e5c7bc176 | ||
| 
						 | 
					c695e9f972 | 
@@ -24,7 +24,7 @@ pkgconfig_DATA = \
 | 
				
			|||||||
BUILT_SOURCES = $(top_srcdir)/.version
 | 
					BUILT_SOURCES = $(top_srcdir)/.version
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
	     .version \
 | 
						     .version \
 | 
				
			||||||
	     contrib/osmo-mgw.spec.in \
 | 
						     README.md \
 | 
				
			||||||
	     debian \
 | 
						     debian \
 | 
				
			||||||
	     git-version-gen \
 | 
						     git-version-gen \
 | 
				
			||||||
	     osmoappdesc.py \
 | 
						     osmoappdesc.py \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								README
									
									
									
									
									
								
							@@ -1,24 +0,0 @@
 | 
				
			|||||||
About OsmoMGW
 | 
					 | 
				
			||||||
=============
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OsmoMGW originated from the OpenBSC project, which started as a minimalistic
 | 
					 | 
				
			||||||
all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
 | 
					 | 
				
			||||||
maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
 | 
					 | 
				
			||||||
IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
 | 
					 | 
				
			||||||
approach to fully independent separate programs as in typical GSM networks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OsmoMGW was one of the parts split off from the old openbsc.git. It originated
 | 
					 | 
				
			||||||
as a solution to merely navigate RTP streams through a NAT, but has since
 | 
					 | 
				
			||||||
matured to a Media Gateway implementation that is capable of streaming RTP for
 | 
					 | 
				
			||||||
2G (AoIP) and 3G (IuCS) GSM networks as well as (still not implemented at time
 | 
					 | 
				
			||||||
of writing) transcoding between TRAU, various RTP payloads and IuUP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The OsmoMGW program exposes an MGCP interface towards clients like OsmoMSC and
 | 
					 | 
				
			||||||
OsmoBSC, and receives and sends RTP streams as configured via MGCP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC (found
 | 
					 | 
				
			||||||
in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Find OsmoMGW issue tracker and wiki online at
 | 
					 | 
				
			||||||
https://osmocom.org/projects/osmo-mgw
 | 
					 | 
				
			||||||
https://osmocom.org/projects/osmo-mgw/wiki
 | 
					 | 
				
			||||||
							
								
								
									
										102
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					osmo-mgw - Osmocom MGW (Media GateWay) Implementation
 | 
				
			||||||
 | 
					=====================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This repository contains a C-language implementation of an MGW (Media
 | 
				
			||||||
 | 
					GateWay) for use [not only] within the 2G (GSM) and/or 3G (UMTS)
 | 
				
			||||||
 | 
					Cellular Network built using Osmocom CNI (Cellular Network
 | 
				
			||||||
 | 
					Infrastructure) software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The OsmoMGW program provides an MGCP interface towards an MGCP call agent
 | 
				
			||||||
 | 
					(client) like OsmoMSC and OsmoBSC, and receives and sends RTP streams as
 | 
				
			||||||
 | 
					configured via the MGCP control plane.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This Media Gateway implementation is capable of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* streaming RTP for 2G (3GPP AoIP and Abis-over-IP)
 | 
				
			||||||
 | 
					* streaming RTP for 3G (IuCS including the IuFP protocol)
 | 
				
			||||||
 | 
					* TDM (E1/T1) based Abis interface with TRAU frames on 16k sub-slots
 | 
				
			||||||
 | 
					* basic support for LCLS (Local Call, Local Switch) related features
 | 
				
			||||||
 | 
					* various built-in translation capabilities
 | 
				
			||||||
 | 
					  * between Abis TRAU frames and RTP formats
 | 
				
			||||||
 | 
					  * between 2G AMR/RTP and 3G AMR/IuFP/RTP
 | 
				
			||||||
 | 
					  * between bandwidth-efficient and octet-aligned AMR
 | 
				
			||||||
 | 
					  * between different standards for encapsulating GSM HR codec frames in RTP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw is typically co-located with
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * osmo-bsc (GSM BSC)
 | 
				
			||||||
 | 
					 * osmo-msc (GSM/UMTS MSC)
 | 
				
			||||||
 | 
					 * osmo-hnbgw (UMTS HNBGW); osmo-mgw implements RTP relay between Iuh
 | 
				
			||||||
 | 
					   and IuCS interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC
 | 
				
			||||||
 | 
					(found in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Homepage
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can find the OsmoMGW issue tracker and wiki online at
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/osmo-mgw> and <https://osmocom.org/projects/osmo-mgw/wiki>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GIT Repository
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can clone from the official osmo-mgw.git repository using
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Documentation
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					User Manuals and VTY reference manuals are [optionally] built in PDF form
 | 
				
			||||||
 | 
					as part of the build process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pre-rendered PDF version of the current "master" can be found at
 | 
				
			||||||
 | 
					[User Manual](https://ftp.osmocom.org/docs/latest/osmomgw-usermanual.pdf)
 | 
				
			||||||
 | 
					as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmomgw-vty-reference.pdf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mailing List
 | 
				
			||||||
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Discussions related to osmo-mgw are happening on the
 | 
				
			||||||
 | 
					openbsc@lists.osmocom.org mailing list, please see
 | 
				
			||||||
 | 
					<https://lists.osmocom.org/mailman/listinfo/openbsc> for subscription
 | 
				
			||||||
 | 
					options and the list archive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please observe the [Osmocom Mailing List
 | 
				
			||||||
 | 
					Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
 | 
				
			||||||
 | 
					when posting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Contributing
 | 
				
			||||||
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Our coding standards are described at
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We use a gerrit based patch submission/review process for managing
 | 
				
			||||||
 | 
					contributions.  Please see
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
 | 
				
			||||||
 | 
					more details
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The current patch queue for osmo-mgw can be seen at
 | 
				
			||||||
 | 
					<https://gerrit.osmocom.org/#/q/project:osmo-mgw+status:open>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					History
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoMGW originated from the OpenBSC project, which started as a minimalistic
 | 
				
			||||||
 | 
					all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
 | 
				
			||||||
 | 
					maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
 | 
				
			||||||
 | 
					IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
 | 
				
			||||||
 | 
					approach to fully independent separate programs as in typical GSM networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoMGW was one of the parts split off from the old openbsc.git. It originated
 | 
				
			||||||
 | 
					as a solution to merely navigate RTP streams through a NAT, but has since
 | 
				
			||||||
 | 
					matured.
 | 
				
			||||||
							
								
								
									
										37
									
								
								TODO-RELEASE
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								TODO-RELEASE
									
									
									
									
									
								
							@@ -1,26 +1,11 @@
 | 
				
			|||||||
# When cleaning up this file upon a release:
 | 
					# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
 | 
				
			||||||
#
 | 
					# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
 | 
				
			||||||
# - Note that the release version number is entirely unrelated to the API
 | 
					# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
 | 
				
			||||||
#   versions. A release version 5.2.3 may happily have an API version of 42:7:5.
 | 
					# LIBVERSION=c:r:a
 | 
				
			||||||
#
 | 
					# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
 | 
				
			||||||
# - Bump API version in src/lib*/Makefile.am files according to chapter
 | 
					# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
 | 
				
			||||||
#   "Library interface versions" of the libtool documentation.
 | 
					# If any interfaces have been added since the last public release: c:r:a + 1.
 | 
				
			||||||
#   https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
 | 
					# If any interfaces have been removed or changed since the last public release: c:r:0.
 | 
				
			||||||
#
 | 
					#library	what			description / commit summary line
 | 
				
			||||||
# - Iff the 'current' API version has changed, rename debian/lib*.install
 | 
					libosmocore		bump_dep; workaround	Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
 | 
				
			||||||
#
 | 
											has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
 | 
				
			||||||
# API version bumping for the impatient:
 | 
					 | 
				
			||||||
# LIBVERSION=c:r:a  (current:revision_of_current:backwards_compat_age)
 | 
					 | 
				
			||||||
# 5:2:4 means that
 | 
					 | 
				
			||||||
# - this implements version 5 of the API;
 | 
					 | 
				
			||||||
# - this is the 2nd (compatible) revision of API version 5;
 | 
					 | 
				
			||||||
# - this is backwards compatible to all APIs since 4 versions ago,
 | 
					 | 
				
			||||||
#   i.e. callers that need API versions from 1 to 5 can use this.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Bumping API versions recipe:
 | 
					 | 
				
			||||||
# If the library source code has changed at all since the last update, r++;
 | 
					 | 
				
			||||||
# If any interfaces have been added, removed, or changed since the last update, c++, r=0;
 | 
					 | 
				
			||||||
# If any interfaces have been added since the last public release, a++;
 | 
					 | 
				
			||||||
# If any interfaces have been removed or changed since the last public release, a=0.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#library		what		description / commit summary line
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							@@ -44,13 +44,13 @@ 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.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
					CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
				
			||||||
CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
					CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
				
			||||||
@@ -204,5 +204,4 @@ AC_OUTPUT(
 | 
				
			|||||||
    doc/manuals/Makefile
 | 
					    doc/manuals/Makefile
 | 
				
			||||||
    contrib/Makefile
 | 
					    contrib/Makefile
 | 
				
			||||||
    contrib/systemd/Makefile
 | 
					    contrib/systemd/Makefile
 | 
				
			||||||
    contrib/osmo-mgw.spec
 | 
					 | 
				
			||||||
    Makefile)
 | 
					    Makefile)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ export deps inst
 | 
				
			|||||||
osmo-clean-workspace.sh
 | 
					osmo-clean-workspace.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir "$deps" || true
 | 
					mkdir "$deps" || true
 | 
				
			||||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
 | 
					osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
					verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
				
			|||||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
					export LD_LIBRARY_PATH="$inst/lib"
 | 
				
			||||||
export PATH="$inst/bin:$PATH"
 | 
					export PATH="$inst/bin:$PATH"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-build-dep.sh libosmo-netif "" --disable-doxygen
 | 
				
			||||||
osmo-build-dep.sh libosmo-abis
 | 
					osmo-build-dep.sh libosmo-abis
 | 
				
			||||||
osmo-build-dep.sh libosmo-netif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Additional configure options and depends
 | 
					# Additional configure options and depends
 | 
				
			||||||
CONFIG=""
 | 
					CONFIG=""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,137 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# spec file for package osmo-mgw
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# All modifications and additions to the file contributed by third parties
 | 
					 | 
				
			||||||
# remain the property of their copyright owners, unless otherwise agreed
 | 
					 | 
				
			||||||
# upon. The license for this file, and modifications and additions to the
 | 
					 | 
				
			||||||
# file, is the same license as for the pristine package itself (unless the
 | 
					 | 
				
			||||||
# license for the pristine package is not an Open Source License, in which
 | 
					 | 
				
			||||||
# case the license is the MIT License). An "Open Source License" is a
 | 
					 | 
				
			||||||
# license that conforms to the Open Source Definition (Version 1.9)
 | 
					 | 
				
			||||||
# published by the Open Source Initiative.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Please submit bugfixes or comments via http://bugs.opensuse.org/
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Name:           osmo-mgw
 | 
					 | 
				
			||||||
Version:        @VERSION@
 | 
					 | 
				
			||||||
Release:        0
 | 
					 | 
				
			||||||
Summary:        Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					 | 
				
			||||||
License:        AGPL-3.0-or-later AND GPL-2.0-or-later
 | 
					 | 
				
			||||||
Group:          Hardware/Mobile
 | 
					 | 
				
			||||||
URL:            https://osmocom.org/projects/osmo-mgw
 | 
					 | 
				
			||||||
Source:         %{name}-%{version}.tar.xz
 | 
					 | 
				
			||||||
BuildRequires:  automake >= 1.9
 | 
					 | 
				
			||||||
BuildRequires:  libtool >= 2
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig >= 0.20
 | 
					 | 
				
			||||||
%if 0%{?suse_version}
 | 
					 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					 | 
				
			||||||
%endif
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.4.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.9.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.9.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.9.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.9.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.9.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.5.0
 | 
					 | 
				
			||||||
%{?systemd_requires}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description
 | 
					 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-client12
 | 
					 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					 | 
				
			||||||
Group:          System/Libraries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-client12
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					 | 
				
			||||||
Requires:       libosmo-mgcp-client12 = %{version}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This subpackage contains libraries and header files for developing
 | 
					 | 
				
			||||||
applications that want to make use of libosmo-mgcp-client.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway server library
 | 
					 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol server library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This subpackage contains libraries and header files for developing
 | 
					 | 
				
			||||||
applications that want to make use of libosmo-mgcp.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%prep
 | 
					 | 
				
			||||||
%setup -q
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%build
 | 
					 | 
				
			||||||
echo "%{version}" >.tarball-version
 | 
					 | 
				
			||||||
autoreconf -fi
 | 
					 | 
				
			||||||
%configure \
 | 
					 | 
				
			||||||
  --disable-static \
 | 
					 | 
				
			||||||
  --docdir=%{_docdir}/%{name} \
 | 
					 | 
				
			||||||
  --with-systemdsystemunitdir=%{_unitdir}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make %{?_smp_mflags}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%install
 | 
					 | 
				
			||||||
%make_install
 | 
					 | 
				
			||||||
find %{buildroot} -type f -name "*.la" -delete -print
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%check
 | 
					 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%post   -n libosmo-mgcp-client12 -p /sbin/ldconfig
 | 
					 | 
				
			||||||
%postun -n libosmo-mgcp-client12 -p /sbin/ldconfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%if 0%{?suse_version}
 | 
					 | 
				
			||||||
%preun
 | 
					 | 
				
			||||||
%service_del_preun osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%postun
 | 
					 | 
				
			||||||
%service_del_postun osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%pre
 | 
					 | 
				
			||||||
%service_add_pre osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%post
 | 
					 | 
				
			||||||
%service_add_post osmo-mgw.service
 | 
					 | 
				
			||||||
%endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files
 | 
					 | 
				
			||||||
%license COPYING
 | 
					 | 
				
			||||||
%doc AUTHORS README
 | 
					 | 
				
			||||||
%dir %{_docdir}/%{name}/examples
 | 
					 | 
				
			||||||
%dir %{_docdir}/%{name}/examples/osmo-mgw
 | 
					 | 
				
			||||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
 | 
					 | 
				
			||||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
 | 
					 | 
				
			||||||
%{_bindir}/osmo-mgw
 | 
					 | 
				
			||||||
%{_unitdir}/osmo-mgw.service
 | 
					 | 
				
			||||||
%dir %{_sysconfdir}/osmocom
 | 
					 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-client12
 | 
					 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.12*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					 | 
				
			||||||
%{_libdir}/pkgconfig/libosmo-mgcp-client.pc
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom/mgcp_client
 | 
					 | 
				
			||||||
%{_includedir}/osmocom/mgcp_client/*.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom/mgcp
 | 
					 | 
				
			||||||
%{_includedir}/osmocom/mgcp/*.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%changelog
 | 
					 | 
				
			||||||
@@ -5,11 +5,15 @@ Wants=network-online.target
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[Service]
 | 
					[Service]
 | 
				
			||||||
Type=simple
 | 
					Type=simple
 | 
				
			||||||
 | 
					LimitNOFILE=65536
 | 
				
			||||||
StateDirectory=osmocom
 | 
					StateDirectory=osmocom
 | 
				
			||||||
WorkingDirectory=%S/osmocom
 | 
					WorkingDirectory=%S/osmocom
 | 
				
			||||||
Restart=always
 | 
					Restart=always
 | 
				
			||||||
 | 
					User=osmocom
 | 
				
			||||||
 | 
					Group=osmocom
 | 
				
			||||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
					ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
RestartSec=2
 | 
					RestartSec=2
 | 
				
			||||||
 | 
					AmbientCapabilities=CAP_SYS_NICE
 | 
				
			||||||
# CPU scheduling policy:
 | 
					# CPU scheduling policy:
 | 
				
			||||||
CPUSchedulingPolicy=rr
 | 
					CPUSchedulingPolicy=rr
 | 
				
			||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
 | 
					# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										140
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										140
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,143 @@
 | 
				
			|||||||
 | 
					osmo-mgw (1.14.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * jenkins.sh: libosmo-netif no longer depends on libosmo-abis
 | 
				
			||||||
 | 
					  * jenkins.sh: Use --disable-doxygen configure param
 | 
				
			||||||
 | 
					  * mgcp-client: Fix wrong value passed to strerror()
 | 
				
			||||||
 | 
					  * mgcp_client_internal.h: Add missing header dependency
 | 
				
			||||||
 | 
					  * mgcp-cli: Mark iofd ptr as NULL when freed
 | 
				
			||||||
 | 
					  * mgcp-cli: Improve error handling around mgcp_msg_gen() return
 | 
				
			||||||
 | 
					  * mgcp-cli: Fix filling in wrong local IP address of SDP Origin o=
 | 
				
			||||||
 | 
					  * mgw: Drop own MGCP extension 'noanswer'
 | 
				
			||||||
 | 
					  * cosmetic: mgw: Fix indentation whitespace
 | 
				
			||||||
 | 
					  * mgcp-client: Fix regression checking null ptr
 | 
				
			||||||
 | 
					  * mgw: Rename and move code freeing endp connection
 | 
				
			||||||
 | 
					  * mgw: Rename and move several get_conn funcs acting on endp object
 | 
				
			||||||
 | 
					  * mgw: mgcp_network.c: Simplify use of conn_rtp ptr
 | 
				
			||||||
 | 
					  * mgw: Clean up access to conn_rtp from conn
 | 
				
			||||||
 | 
					  * mgw: Avoid 2nd lookup of conn in endp during CRCX
 | 
				
			||||||
 | 
					  * cosmetic: mgw: iuup: Update comment
 | 
				
			||||||
 | 
					  * mgw: constify mgcp_endp_avail() param
 | 
				
			||||||
 | 
					  * mgcp_endp: Add helpers accessing endp connections
 | 
				
			||||||
 | 
					  * mgw: mgcp_protocol: assert freeing last conn allows creating new conn
 | 
				
			||||||
 | 
					  * mgw: Split conn mode parsing and applying into conn
 | 
				
			||||||
 | 
					  * mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables
 | 
				
			||||||
 | 
					  * mgw: Use bool instead of int in local var
 | 
				
			||||||
 | 
					  * Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port()
 | 
				
			||||||
 | 
					  * mgw: Split mgcp_rtp_end to its own file
 | 
				
			||||||
 | 
					  * mgw: Introduce mgcp_rtp_end_init()
 | 
				
			||||||
 | 
					  * mgw: Introduce struct mgcp_codecset struct
 | 
				
			||||||
 | 
					  * mgw: Cleanup rtp_endp fields in its own function
 | 
				
			||||||
 | 
					  * mgw: Move force_ptime logic outside of main CRCX func handler
 | 
				
			||||||
 | 
					  * mgw: Move several params setting to mgcp_rtp_end_init()
 | 
				
			||||||
 | 
					  * mgw: Simplify and redo code around ssrc patch feature
 | 
				
			||||||
 | 
					  * mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
 | 
				
			||||||
 | 
					  * mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
 | 
				
			||||||
 | 
					  * mgw: CRCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: MDCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: DLCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: Decouple SDP parsing step from conn obj update
 | 
				
			||||||
 | 
					  * mgw: Remove wrong TODO comment
 | 
				
			||||||
 | 
					  * mgw: MDCX: Simplify early return code paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Mychaela N. Falconia ]
 | 
				
			||||||
 | 
					  * E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
 | 
				
			||||||
 | 
					  * E1: replace idle_tf_efr[] with a better version
 | 
				
			||||||
 | 
					  * E1: replace idle_tf_fr[] with a better version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Wed, 12 Feb 2025 12:30:33 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.13.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_network: use an uint16_t to store the port number
 | 
				
			||||||
 | 
					  * mgcp_network: add missing ntohs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * tests/mgcp/mgcp_test: Add some extra asserts in code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Thu, 12 Sep 2024 13:53:19 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.13.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * add mgcp_conn_rtp_type_names[]
 | 
				
			||||||
 | 
					  * mgcp_parse_audio_port_pt(): fix buffer overflow
 | 
				
			||||||
 | 
					  * client: replace two assertions with graceful error handling
 | 
				
			||||||
 | 
					  * systemd,manual: set LimitNOFILE=65536
 | 
				
			||||||
 | 
					  * IuUP: allow Initialization from any address if not yet set
 | 
				
			||||||
 | 
					  * check_rtp_origin: drop special case for legacy IuUP hack
 | 
				
			||||||
 | 
					  * mgcp_client_test: fix function name
 | 
				
			||||||
 | 
					  * fix possible NULL deref on early media
 | 
				
			||||||
 | 
					  * client: move some items to internal header
 | 
				
			||||||
 | 
					  * client: safely handle dealloc on event dispatch
 | 
				
			||||||
 | 
					  * build: move mgcp/*.h to noinst_HEADERS, drop RPM libosmo-mgcp-devel
 | 
				
			||||||
 | 
					  * client: deprecate legacy API
 | 
				
			||||||
 | 
					  * client: collapse codecs[] and ptmap[]; allow codec variants
 | 
				
			||||||
 | 
					  * client: allow MGCP_MAX_CODECS entries
 | 
				
			||||||
 | 
					  * client SDP: more verbose error logging
 | 
				
			||||||
 | 
					  * mgcp_client_test: add test_parse_response()
 | 
				
			||||||
 | 
					  * drop (now) unused code
 | 
				
			||||||
 | 
					  * tests/mgcp: add update_exp target
 | 
				
			||||||
 | 
					  * drop get_net_downlink_format_cb
 | 
				
			||||||
 | 
					  * drop cfg 'sdp audio fmtp-extra'
 | 
				
			||||||
 | 
					  * mgcp_codec_decide: remove redundant lookup
 | 
				
			||||||
 | 
					  * tweak DEBUG log
 | 
				
			||||||
 | 
					  * mgcp_test: fix false negatives in test output
 | 
				
			||||||
 | 
					  * mgw: do not fail MGCP on codec mismatch
 | 
				
			||||||
 | 
					  * mgcp-client: always send 'm=audio' line
 | 
				
			||||||
 | 
					  * mgcp_test.c: verify osmo-mgw accepts m=audio 0
 | 
				
			||||||
 | 
					  * mgcp_test.c: fix various missing '\r' and '\n'
 | 
				
			||||||
 | 
					  * mgcp_test: test a=ptime:20, not 40
 | 
				
			||||||
 | 
					  * mgcp_test: add CRCX for IUFP in sendrecv
 | 
				
			||||||
 | 
					  * do not FAIL on CRCX in sendrecv mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Keith Whyte ]
 | 
				
			||||||
 | 
					  * vty and log: also show local port for RTP conns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Andreas Eversberg ]
 | 
				
			||||||
 | 
					  * Use uniform log format for default config files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp_network: Improve err logging when rtp pkt from unexpected origin comes in
 | 
				
			||||||
 | 
					  * cosmetic: Fix line indentation
 | 
				
			||||||
 | 
					  * IuUP: Allow Initialization with set rem IP address and unset rem port
 | 
				
			||||||
 | 
					  * mgcp-client: Transmit remote IP addr in CRCX if known and port=0
 | 
				
			||||||
 | 
					  * Fix IuUP RTP hdr seqnr field not incremented
 | 
				
			||||||
 | 
					  * iuup: Increment RTP hdr seqnr even if Tx over UDP fails
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * mgcp: simplify getting msgb tail in mgcp_msg_terminate_nul()
 | 
				
			||||||
 | 
					  * mgcp: reserve once byte for '\0' in mgcp_do_read()
 | 
				
			||||||
 | 
					  * mgcp: correctly put NUL character in mgcp_msg_terminate_nul()
 | 
				
			||||||
 | 
					  * build: include README into the release tarball
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ neels ]
 | 
				
			||||||
 | 
					  * Revert "drop (now) unused code"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Convert README to README.md and expand like in other projects
 | 
				
			||||||
 | 
					  * migrate mgcp_client from osmo_wqueue to osmo_io
 | 
				
			||||||
 | 
					  * mgw: Add our usual SIGABRT, SIGUSR1 signal handlers
 | 
				
			||||||
 | 
					  * don't log useless "transcoding disabled" message
 | 
				
			||||||
 | 
					  * remove strange loop for non-existant transcoding support
 | 
				
			||||||
 | 
					  * simplify unused transcoding/processing call-back
 | 
				
			||||||
 | 
					  * remove osmo_fd from mgcp_create_bind()
 | 
				
			||||||
 | 
					  * Change msgb ownership in processing of received msgb
 | 
				
			||||||
 | 
					  * cosmetic: make linter happy
 | 
				
			||||||
 | 
					  * Convert RTP/RTCP/OSMUX I/O from osmo_fd to osmo_io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * contrib: remove rpm spec file
 | 
				
			||||||
 | 
					  * contrib/systemd: run as osmocom user
 | 
				
			||||||
 | 
					  * doc: example configs: fix deprecation warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Mychaela N. Falconia ]
 | 
				
			||||||
 | 
					  * E1: support HRv1 codec on both 16k and 8k subslots
 | 
				
			||||||
 | 
					  * fix E1 TS output when used with osmo-e1d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Wed, 24 Jul 2024 15:44:47 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-mgw (1.12.1) unstable; urgency=medium
 | 
					osmo-mgw (1.12.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,10 +6,10 @@ Build-Depends: debhelper (>= 10),
 | 
				
			|||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.9.0),
 | 
					               libosmocore-dev (>= 1.11.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.4.0),
 | 
					               libosmo-netif-dev (>= 1.6.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.5.0),
 | 
					               libosmo-abis-dev (>= 2.0.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.5.0)
 | 
					               osmo-gsm-manuals-dev (>= 1.6.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-client14
 | 
				
			||||||
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-client14 (= ${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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								debian/postinst
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								debian/postinst
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#!/bin/sh -e
 | 
				
			||||||
 | 
					case "$1" in
 | 
				
			||||||
 | 
						configure)
 | 
				
			||||||
 | 
							# Create the osmocom group and user (if it doesn't exist yet)
 | 
				
			||||||
 | 
							if ! getent group osmocom >/dev/null; then
 | 
				
			||||||
 | 
								groupadd --system osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							if ! getent passwd osmocom >/dev/null; then
 | 
				
			||||||
 | 
								useradd \
 | 
				
			||||||
 | 
									--system \
 | 
				
			||||||
 | 
									--gid osmocom \
 | 
				
			||||||
 | 
									--home-dir /var/lib/osmocom \
 | 
				
			||||||
 | 
									--shell /sbin/nologin \
 | 
				
			||||||
 | 
									--comment "Open Source Mobile Communications" \
 | 
				
			||||||
 | 
									osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Fix permissions of previous (root-owned) install (OS#4107)
 | 
				
			||||||
 | 
							if dpkg --compare-versions "$2" le "1.13.0"; then
 | 
				
			||||||
 | 
								if [ -e /etc/osmocom/osmo-mgw.cfg ]; then
 | 
				
			||||||
 | 
									chown -v osmocom:osmocom /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
									chmod -v 0660 /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if [ -d /etc/osmocom ]; then
 | 
				
			||||||
 | 
									chown -v root:osmocom /etc/osmocom
 | 
				
			||||||
 | 
									chmod -v 2775 /etc/osmocom
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mkdir -p /var/lib/osmocom
 | 
				
			||||||
 | 
								chown -R -v osmocom:osmocom /var/lib/osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dh_installdeb(1) will replace this with shell code automatically
 | 
				
			||||||
 | 
					# generated by other debhelper scripts.
 | 
				
			||||||
 | 
					#DEBHELPER#
 | 
				
			||||||
@@ -1,20 +1,25 @@
 | 
				
			|||||||
!
 | 
					!
 | 
				
			||||||
! MGCP configuration example
 | 
					! MGCP configuration example
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
 | 
					log stderr
 | 
				
			||||||
 | 
					 logging color 1
 | 
				
			||||||
 | 
					 logging print category-hex 0
 | 
				
			||||||
 | 
					 logging print category 1
 | 
				
			||||||
 | 
					 logging timestamp 0
 | 
				
			||||||
 | 
					 logging print file basename last
 | 
				
			||||||
 | 
					 logging print level 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
e1_input
 | 
					e1_input
 | 
				
			||||||
 e1_line 0 driver dahdi
 | 
					 e1_line 0 driver dahdi
 | 
				
			||||||
 e1_line 0 port 0
 | 
					 e1_line 0 port 0
 | 
				
			||||||
mgcp
 | 
					mgcp
 | 
				
			||||||
  bind ip 127.0.0.1
 | 
					  bind ip 127.0.0.1
 | 
				
			||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16001
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-dscp 46
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					 | 
				
			||||||
  sdp audio payload name GSM
 | 
					 | 
				
			||||||
  number endpoints 512
 | 
					  number endpoints 512
 | 
				
			||||||
  loop 0
 | 
					 | 
				
			||||||
  force-realloc 1
 | 
					  force-realloc 1
 | 
				
			||||||
  rtcp-omit
 | 
					  rtcp-omit
 | 
				
			||||||
  rtp-patch ssrc
 | 
					  rtp-patch ssrc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,22 @@
 | 
				
			|||||||
!
 | 
					!
 | 
				
			||||||
! MGCP configuration example
 | 
					! MGCP configuration example
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
 | 
					log stderr
 | 
				
			||||||
 | 
					 logging color 1
 | 
				
			||||||
 | 
					 logging print category-hex 0
 | 
				
			||||||
 | 
					 logging print category 1
 | 
				
			||||||
 | 
					 logging timestamp 0
 | 
				
			||||||
 | 
					 logging print file basename last
 | 
				
			||||||
 | 
					 logging print level 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mgcp
 | 
					mgcp
 | 
				
			||||||
  bind ip 127.0.0.1
 | 
					  bind ip 127.0.0.1
 | 
				
			||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16001
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-dscp 46
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					 | 
				
			||||||
  sdp audio payload name GSM
 | 
					 | 
				
			||||||
  number endpoints 512
 | 
					  number endpoints 512
 | 
				
			||||||
  loop 0
 | 
					 | 
				
			||||||
  force-realloc 1
 | 
					  force-realloc 1
 | 
				
			||||||
  rtcp-omit
 | 
					  rtcp-omit
 | 
				
			||||||
  rtp-patch ssrc
 | 
					  rtp-patch ssrc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,3 +23,20 @@ arguments:
 | 
				
			|||||||
	Disable colors for logging to stderr. This has mostly been
 | 
						Disable colors for logging to stderr. This has mostly been
 | 
				
			||||||
	deprecated by VTY based logging configuration, see <<logging>>
 | 
						deprecated by VTY based logging configuration, see <<logging>>
 | 
				
			||||||
	for more information.
 | 
						for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Configure limits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When servicing hundreds of media endpoints, it may be necessary to adjust the
 | 
				
			||||||
 | 
					operating system's limit on open file descriptors for the osmo-mgw process. A
 | 
				
			||||||
 | 
					typical default limit imposed by operating systems is 1024; this would be
 | 
				
			||||||
 | 
					exceeded by, for example, about 256 active voice calls with 4 RTP/RTPC ports
 | 
				
			||||||
 | 
					each, sockets for other interfaces not considered yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It should be ok to set an OS limit on open file descriptors as high as 65536
 | 
				
			||||||
 | 
					for osmo-mgw, which practically rules out failure from running out of file
 | 
				
			||||||
 | 
					descriptors anywhere (<16,000 active calls).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When using systemd, the file descriptor limit may be adjusted in the service
 | 
				
			||||||
 | 
					file by the `LimitNOFILE` setting ("Number of Open FILE descriptors"). OsmoMGW
 | 
				
			||||||
 | 
					ships a systemd service file with a high LimitNOFILE setting.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ nobase_include_HEADERS = \
 | 
				
			|||||||
	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 \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_pool.h \
 | 
						osmocom/mgcp_client/mgcp_client_pool.h \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	osmocom/mgcp/mgcp.h \
 | 
						osmocom/mgcp/mgcp.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_common.h \
 | 
						osmocom/mgcp/mgcp_common.h \
 | 
				
			||||||
	osmocom/mgcp/osmux.h \
 | 
						osmocom/mgcp/osmux.h \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
noinst_HEADERS = \
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	vty.h \
 | 
						vty.h \
 | 
				
			||||||
	mgcp_msg.h \
 | 
						mgcp_msg.h \
 | 
				
			||||||
 | 
						mgcp_codec.h \
 | 
				
			||||||
	mgcp_conn.h \
 | 
						mgcp_conn.h \
 | 
				
			||||||
	mgcp_stat.h \
 | 
						mgcp_stat.h \
 | 
				
			||||||
	mgcp_endp.h \
 | 
						mgcp_endp.h \
 | 
				
			||||||
@@ -13,4 +14,5 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_network.h \
 | 
						mgcp_network.h \
 | 
				
			||||||
	mgcp_protocol.h \
 | 
						mgcp_protocol.h \
 | 
				
			||||||
	mgcp_iuup.h \
 | 
						mgcp_iuup.h \
 | 
				
			||||||
 | 
						mgcp_rtp_end.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/write_queue.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
@@ -70,12 +71,10 @@ typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Return:
 | 
					 * Return:
 | 
				
			||||||
 *   <  0 in case no audio was processed
 | 
					 *   <  0 in case no audio was processed
 | 
				
			||||||
 *   >= 0 in case audio was processed. The remaining payload
 | 
					 *   >= 0 in case audio was processed.
 | 
				
			||||||
 *   length will be returned.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
 | 
					typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
 | 
				
			||||||
			       struct mgcp_rtp_end *dst_end,
 | 
								       struct mgcp_rtp_end *dst_end, struct msgb *msg);
 | 
				
			||||||
			       char *data, int *len, int buf_size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,8 +137,6 @@ struct mgcp_config {
 | 
				
			|||||||
	mgcp_processing rtp_processing_cb;
 | 
						mgcp_processing rtp_processing_cb;
 | 
				
			||||||
	mgcp_processing_setup setup_rtp_processing_cb;
 | 
						mgcp_processing_setup setup_rtp_processing_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_get_format get_net_downlink_format_cb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct osmo_wqueue gw_fd;
 | 
						struct osmo_wqueue gw_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mgcp_port_range net_ports;
 | 
						struct mgcp_port_range net_ports;
 | 
				
			||||||
@@ -208,6 +205,5 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
 | 
				
			|||||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
					int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
					int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio);
 | 
				
			||||||
		     uint8_t prio);
 | 
					int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len);
 | 
				
			||||||
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,9 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
					#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
				
			||||||
@@ -8,14 +12,37 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define PTYPE_UNDEFINED (-1)
 | 
					#define PTYPE_UNDEFINED (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_rtp_codec {
 | 
				
			||||||
 | 
						uint32_t rate;
 | 
				
			||||||
 | 
						int channels;
 | 
				
			||||||
 | 
						uint32_t frame_duration_num;
 | 
				
			||||||
 | 
						uint32_t frame_duration_den;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int payload_type;
 | 
				
			||||||
 | 
						char audio_name[64];
 | 
				
			||||||
 | 
						char subtype_name[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
					 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst);
 | 
					 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
					 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
					 | 
				
			||||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
					bool mgcp_codec_amr_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);
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_codecset {
 | 
				
			||||||
 | 
						/* currently selected audio codec */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
 | 
						/* array with assigned audio codecs to choose from (SDP) */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						/* number of assigned audio codecs (SDP) */
 | 
				
			||||||
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
 | 
				
			||||||
 | 
					void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
 | 
				
			||||||
 | 
					int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
 | 
				
			||||||
 | 
								    const char *audio_name, const struct mgcp_codec_param *param);
 | 
				
			||||||
 | 
					int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
 | 
				
			||||||
 | 
					const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
				
			||||||
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,11 +68,11 @@ struct mgcp_codec_param {
 | 
				
			|||||||
/* Ensure that the msg->l2h is NUL terminated. */
 | 
					/* Ensure that the msg->l2h is NUL terminated. */
 | 
				
			||||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
					static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
 | 
						unsigned char *tail = msg->tail; /* char after l2 data */
 | 
				
			||||||
	if (tail[-1] == '\0')
 | 
						if (tail[-1] == '\0')
 | 
				
			||||||
		/* nothing to do */;
 | 
							/* nothing to do */;
 | 
				
			||||||
	else if (msgb_tailroom(msg) > 0)
 | 
						else if (msgb_tailroom(msg) > 0)
 | 
				
			||||||
		tail[0] = '\0';
 | 
							msgb_put_u8(msg, (uint8_t)'\0');
 | 
				
			||||||
	else if (tail[-1] == '\r' || tail[-1] == '\n')
 | 
						else if (tail[-1] == '\r' || tail[-1] == '\n')
 | 
				
			||||||
		tail[-1] = '\0';
 | 
							tail[-1] = '\0';
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,11 +24,14 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
#include <osmocom/core/linuxlist.h>
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/gsm/iuup.h>
 | 
					#include <osmocom/gsm/iuup.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
@@ -49,6 +52,11 @@ enum mgcp_conn_rtp_type {
 | 
				
			|||||||
	MGCP_RTP_OSMUX,
 | 
						MGCP_RTP_OSMUX,
 | 
				
			||||||
	MGCP_RTP_IUUP,
 | 
						MGCP_RTP_IUUP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					extern const struct value_string mgcp_conn_rtp_type_names[];
 | 
				
			||||||
 | 
					static inline const char *mgcp_conn_rtp_type_name(enum mgcp_conn_rtp_type val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return get_value_string(mgcp_conn_rtp_type_names, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
 *  contains a useful connection description (currently only RTP) */
 | 
					 *  contains a useful connection description (currently only RTP) */
 | 
				
			||||||
@@ -232,15 +240,16 @@ static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	return conn->type == MGCP_RTP_IUUP;
 | 
						return conn->type == MGCP_RTP_IUUP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
 | 
				
			||||||
 | 
						return &conn->u.rtp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
					struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			||||||
				  enum mgcp_conn_type type, char *name);
 | 
									  enum mgcp_conn_type type, char *name);
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
 | 
					void mgcp_conn_free(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
					int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode);
 | 
				
			||||||
					const char *id);
 | 
					 | 
				
			||||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
 | 
					 | 
				
			||||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
					char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
 | 
					struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,11 +138,20 @@ 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,
 | 
				
			||||||
					struct mgcp_config *cfg);
 | 
										struct mgcp_config *cfg);
 | 
				
			||||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
 | 
					bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
 | 
				
			||||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
 | 
				
			||||||
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
 | 
					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);
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										const char *id);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,8 @@
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
struct mgcp_parse_data;
 | 
					struct mgcp_parse_data;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
@@ -34,14 +36,14 @@ struct mgcp_trunk;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
 | 
					void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
 | 
					enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg);
 | 
				
			||||||
			 struct mgcp_conn *conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
					int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
				
			||||||
 | 
					int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_osmux_cid(const char *line);
 | 
					int mgcp_parse_osmux_cid(const char *line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
 | 
					bool mgcp_check_param(const char *line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
 | 
					int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -73,66 +74,6 @@ struct mgcp_rtp_state {
 | 
				
			|||||||
	uint32_t alt_rtp_tx_ssrc;
 | 
						uint32_t alt_rtp_tx_ssrc;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_codec {
 | 
					 | 
				
			||||||
	uint32_t rate;
 | 
					 | 
				
			||||||
	int channels;
 | 
					 | 
				
			||||||
	uint32_t frame_duration_num;
 | 
					 | 
				
			||||||
	uint32_t frame_duration_den;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int payload_type;
 | 
					 | 
				
			||||||
	char audio_name[64];
 | 
					 | 
				
			||||||
	char subtype_name[64];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool param_present;
 | 
					 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
					 | 
				
			||||||
struct mgcp_rtp_end {
 | 
					 | 
				
			||||||
	/* remote IP address of the RTP socket */
 | 
					 | 
				
			||||||
	struct osmo_sockaddr addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* in network byte order */
 | 
					 | 
				
			||||||
	int rtcp_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* currently selected audio codec */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* array with assigned audio codecs to choose from (SDP) */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* number of assigned audio codecs (SDP) */
 | 
					 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* per endpoint data */
 | 
					 | 
				
			||||||
	int  frames_per_packet;
 | 
					 | 
				
			||||||
	uint32_t packet_duration_ms;
 | 
					 | 
				
			||||||
	int maximum_packet_time; /* -1: not set */
 | 
					 | 
				
			||||||
	char *fmtp_extra;
 | 
					 | 
				
			||||||
	/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
					 | 
				
			||||||
	bool output_enabled;
 | 
					 | 
				
			||||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
					 | 
				
			||||||
	int force_output_ptime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* RTP patching */
 | 
					 | 
				
			||||||
	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
 | 
					 | 
				
			||||||
	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
					 | 
				
			||||||
	int force_aligned_timing;
 | 
					 | 
				
			||||||
	bool rfc5993_hr_convert;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Each end has a separate socket for RTP and RTCP */
 | 
					 | 
				
			||||||
	struct osmo_fd rtp;
 | 
					 | 
				
			||||||
	struct osmo_fd rtcp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
					 | 
				
			||||||
	int local_port;
 | 
					 | 
				
			||||||
	/* where the endpoint RTP connection binds to, set during CRCX and
 | 
					 | 
				
			||||||
	 * possibly updated during MDCX */
 | 
					 | 
				
			||||||
	char local_addr[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_rtp_tap {
 | 
					struct mgcp_rtp_tap {
 | 
				
			||||||
	/* is this tap active (1) or not (0) */
 | 
						/* is this tap active (1) or not (0) */
 | 
				
			||||||
	int enabled;
 | 
						int enabled;
 | 
				
			||||||
@@ -150,9 +91,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
 | 
				
			|||||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
 | 
					int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
 | 
				
			||||||
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
					int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
 | 
				
			||||||
			   struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
 | 
					 | 
				
			||||||
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
					void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			||||||
			  struct mgcp_rtp_state *state,
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
			  struct mgcp_rtp_end *rtp_end,
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
@@ -160,8 +99,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* payload processing default functions */
 | 
					/* payload processing default functions */
 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
 | 
				
			||||||
				char *data, int *len, int buf_size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
					int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
				      struct mgcp_conn_rtp *conn_dst,
 | 
									      struct mgcp_conn_rtp *conn_dst,
 | 
				
			||||||
@@ -181,7 +119,7 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
 | 
				
			|||||||
				 int id, int inc);
 | 
									 int id, int inc);
 | 
				
			||||||
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
				 int id);
 | 
									 int id);
 | 
				
			||||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
					void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
				
			||||||
uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
					uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
 | 
					int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,73 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_RTP_PORT_UNSET (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_parse_sdp {
 | 
				
			||||||
 | 
						int ptime;
 | 
				
			||||||
 | 
						int maxptime;
 | 
				
			||||||
 | 
						int rtp_port;
 | 
				
			||||||
 | 
						struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codecset cset;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET;
 | 
				
			||||||
 | 
						sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET;
 | 
				
			||||||
 | 
						sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET;
 | 
				
			||||||
 | 
						sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC };
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&sdp->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_parse_hdr_pars {
 | 
				
			||||||
 | 
						const char *local_options;
 | 
				
			||||||
 | 
						const char *callid;
 | 
				
			||||||
 | 
						const char *connid;
 | 
				
			||||||
 | 
						enum mgcp_connection_mode mode;
 | 
				
			||||||
 | 
						int remote_osmux_cid;
 | 
				
			||||||
 | 
						bool have_sdp;
 | 
				
			||||||
 | 
						/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
				
			||||||
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*hpars = (struct mgcp_parse_hdr_pars){
 | 
				
			||||||
 | 
							.local_options = NULL,
 | 
				
			||||||
 | 
							.callid = NULL,
 | 
				
			||||||
 | 
							.connid = NULL,
 | 
				
			||||||
 | 
							.mode = MGCP_CONN_NONE,
 | 
				
			||||||
 | 
							.remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET,
 | 
				
			||||||
 | 
							.have_sdp = false,
 | 
				
			||||||
 | 
							.x_osmo_ign = 0,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Internal structure while parsing a request */
 | 
					/* Internal structure while parsing a request */
 | 
				
			||||||
struct mgcp_parse_data {
 | 
					struct mgcp_parse_data {
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
						char *save;
 | 
				
			||||||
 | 
						/* MGCP Header: */
 | 
				
			||||||
	char *epname;
 | 
						char *epname;
 | 
				
			||||||
	char *trans;
 | 
						char *trans;
 | 
				
			||||||
	char *save;
 | 
						struct mgcp_parse_hdr_pars hpars;
 | 
				
			||||||
 | 
						/* MGCP Body: */
 | 
				
			||||||
 | 
						struct mgcp_parse_sdp sdp;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Local connection options */
 | 
					/* Local connection options */
 | 
				
			||||||
@@ -23,8 +85,12 @@ int check_local_cx_options(void *ctx, const char *options);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_end;
 | 
					struct mgcp_rtp_end;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
					 | 
				
			||||||
			 struct mgcp_rtp_end *rtp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
					uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
				
			||||||
				  const struct mgcp_rtp_end *rtp);
 | 
									  const struct mgcp_rtp_end *rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string mgcp_connection_mode_strs[];
 | 
				
			||||||
 | 
					static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return get_value_string(mgcp_connection_mode_strs, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
				
			||||||
 | 
					struct mgcp_rtp_end {
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp; /* backpointer */
 | 
				
			||||||
 | 
						/* remote IP address of the RTP socket */
 | 
				
			||||||
 | 
						struct osmo_sockaddr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* in network byte order */
 | 
				
			||||||
 | 
						uint16_t rtcp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mgcp_rtp_codecset cset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* per endpoint data */
 | 
				
			||||||
 | 
						int  frames_per_packet;
 | 
				
			||||||
 | 
						uint32_t packet_duration_ms;
 | 
				
			||||||
 | 
						int maximum_packet_time; /* -1: not set */
 | 
				
			||||||
 | 
						/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
				
			||||||
 | 
						bool output_enabled;
 | 
				
			||||||
 | 
						/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
				
			||||||
 | 
						int force_output_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* RTP patching */
 | 
				
			||||||
 | 
						bool force_constant_ssrc;
 | 
				
			||||||
 | 
						/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
				
			||||||
 | 
						int force_aligned_timing;
 | 
				
			||||||
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Each end has a separate socket for RTP and RTCP */
 | 
				
			||||||
 | 
						struct osmo_io_fd *rtp;
 | 
				
			||||||
 | 
						struct osmo_io_fd *rtcp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
				
			||||||
 | 
						int local_port;
 | 
				
			||||||
 | 
						/* where the endpoint RTP connection binds to, set during CRCX and
 | 
				
			||||||
 | 
						 * possibly updated during MDCX */
 | 
				
			||||||
 | 
						char local_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms);
 | 
				
			||||||
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end);
 | 
				
			||||||
@@ -22,9 +22,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
					struct mgcp_parse_data;
 | 
				
			||||||
			struct mgcp_conn_rtp *conn,
 | 
					
 | 
				
			||||||
			struct mgcp_parse_data *p);
 | 
					int mgcp_parse_sdp_data(struct mgcp_parse_data *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
					int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			||||||
			    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
								    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/gsm/i460_mux.h>
 | 
					#include <osmocom/gsm/i460_mux.h>
 | 
				
			||||||
#include <osmocom/abis/e1_input.h>
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
					#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
 | 
					#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
 | 
				
			||||||
LOGP(cat, level, "trunk:%u " fmt, \
 | 
					LOGP(cat, level, "trunk:%u " fmt, \
 | 
				
			||||||
     trunk ? trunk->trunk_nr : 0, \
 | 
					     trunk ? trunk->trunk_nr : 0, \
 | 
				
			||||||
@@ -27,7 +28,6 @@ struct mgcp_trunk {
 | 
				
			|||||||
	unsigned int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
	enum mgcp_trunk_type trunk_type;
 | 
						enum mgcp_trunk_type trunk_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *audio_fmtp_extra;
 | 
					 | 
				
			||||||
	int audio_send_ptime;
 | 
						int audio_send_ptime;
 | 
				
			||||||
	int audio_send_name;
 | 
						int audio_send_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +35,7 @@ struct mgcp_trunk {
 | 
				
			|||||||
	int keepalive_interval;
 | 
						int keepalive_interval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RTP patching */
 | 
						/* RTP patching */
 | 
				
			||||||
	int force_constant_ssrc; /* 0: don't, 1: once */
 | 
						bool force_constant_ssrc;
 | 
				
			||||||
	int force_aligned_timing;
 | 
						int force_aligned_timing;
 | 
				
			||||||
	bool rfc5993_hr_convert;
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,6 +79,7 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
 | 
				
			|||||||
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
 | 
					struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
 | 
				
			||||||
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
 | 
					int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
 | 
				
			||||||
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
 | 
					struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
 | 
				
			||||||
 | 
					int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
					/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
				
			||||||
 * use this define constant as ID when allocating a virtual trunk. Other
 | 
					 * use this define constant as ID when allocating a virtual trunk. Other
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,27 +79,7 @@ struct ptmap {
 | 
				
			|||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_head {
 | 
					int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
 | 
				
			||||||
	int response_code;
 | 
					 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
					 | 
				
			||||||
	char comment[MGCP_COMMENT_MAXLEN];
 | 
					 | 
				
			||||||
	char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
					 | 
				
			||||||
	char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	bool x_osmo_osmux_use;
 | 
					 | 
				
			||||||
	uint8_t x_osmo_osmux_cid;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_response {
 | 
					 | 
				
			||||||
	char *body;
 | 
					 | 
				
			||||||
	struct mgcp_response_head head;
 | 
					 | 
				
			||||||
	uint16_t audio_port;
 | 
					 | 
				
			||||||
	char audio_ip[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
	unsigned int ptime;
 | 
					 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int codecs_len;
 | 
					 | 
				
			||||||
	struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int ptmap_len;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum mgcp_verb {
 | 
					enum mgcp_verb {
 | 
				
			||||||
	MGCP_VERB_CRCX,
 | 
						MGCP_VERB_CRCX,
 | 
				
			||||||
@@ -109,37 +89,6 @@ enum mgcp_verb {
 | 
				
			|||||||
	MGCP_VERB_RSIP,
 | 
						MGCP_VERB_RSIP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_ENDPOINT	0x0001
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CALL_ID	0x0002
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CONN_ID	0x0004
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_msg {
 | 
					 | 
				
			||||||
	enum mgcp_verb verb;
 | 
					 | 
				
			||||||
	/* See MGCP_MSG_PRESENCE_* constants */
 | 
					 | 
				
			||||||
	uint32_t presence;
 | 
					 | 
				
			||||||
	char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	unsigned int call_id;
 | 
					 | 
				
			||||||
	char *conn_id;
 | 
					 | 
				
			||||||
	uint16_t audio_port;
 | 
					 | 
				
			||||||
	char *audio_ip;
 | 
					 | 
				
			||||||
	enum mgcp_connection_mode conn_mode;
 | 
					 | 
				
			||||||
	unsigned int ptime;
 | 
					 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int codecs_len;
 | 
					 | 
				
			||||||
	struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int ptmap_len;
 | 
					 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
					 | 
				
			||||||
	bool x_osmo_osmux_use;
 | 
					 | 
				
			||||||
	int x_osmo_osmux_cid; /* -1 is wildcard */
 | 
					 | 
				
			||||||
	bool param_present;
 | 
					 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
 | 
					struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
 | 
				
			||||||
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_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);
 | 
				
			||||||
@@ -161,20 +110,8 @@ const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
 | 
				
			|||||||
const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
					const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
				
			||||||
				  uint8_t rate, uint8_t offset);
 | 
									  uint8_t rate, uint8_t offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Invoked when an MGCP response is received or sending failed.  When the
 | 
					 | 
				
			||||||
 * response is passed as NULL, this indicates failure during transmission. */
 | 
					 | 
				
			||||||
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
 | 
					 | 
				
			||||||
int mgcp_response_parse_params(struct mgcp_response *r);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
					 | 
				
			||||||
		   mgcp_response_cb_t response_cb, void *priv);
 | 
					 | 
				
			||||||
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum mgcp_connection_mode;
 | 
					enum mgcp_connection_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
 | 
					 | 
				
			||||||
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern const struct value_string mgcp_client_connection_mode_strs[];
 | 
					extern const struct value_string mgcp_client_connection_mode_strs[];
 | 
				
			||||||
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
 | 
					static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,11 @@ struct mgcp_conn_peer {
 | 
				
			|||||||
	/*! RTP packetization interval (optional) */
 | 
						/*! RTP packetization interval (optional) */
 | 
				
			||||||
	unsigned int ptime;
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! RTP codec list (optional) */
 | 
						/*! Deprecated. Use only ptmap[].codec in new code. */
 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
						enum mgcp_codecs codecs[MGCP_MAX_CODECS]
 | 
				
			||||||
 | 
							OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
 | 
				
			||||||
	/*! Number of codecs in RTP codec list (optional) */
 | 
						unsigned int codecs_len
 | 
				
			||||||
	unsigned int codecs_len;
 | 
							OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! RTP payload type map (optional, only needed when payload types are
 | 
						/*! RTP payload type map (optional, only needed when payload types are
 | 
				
			||||||
	 * used that differ from what IANA/3GPP defines) */
 | 
						 * used that differ from what IANA/3GPP defines) */
 | 
				
			||||||
@@ -64,11 +64,15 @@ struct mgcp_conn_peer {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
					struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
				
			||||||
				       uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
 | 
									       uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_alloc() and osmo_mgcpc_ep_ci_add() instead");
 | 
				
			||||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
					int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_request() instead");
 | 
				
			||||||
 | 
					void mgcp_conn_delete(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_dlcx() instead");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
 | 
					const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci.mgcp_ci_str instead");
 | 
				
			||||||
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
 | 
					struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
 | 
					const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_CB_MGCP_TRANS_ID 0
 | 
					#define MSGB_CB_MGCP_TRANS_ID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Struct that holds one endpoint name */
 | 
					/* Struct that holds one endpoint name */
 | 
				
			||||||
@@ -13,7 +15,7 @@ struct reset_ep {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct mgcp_client {
 | 
					struct mgcp_client {
 | 
				
			||||||
	struct mgcp_client_conf actual;
 | 
						struct mgcp_client_conf actual;
 | 
				
			||||||
	struct osmo_wqueue wq;
 | 
						struct osmo_io_fd *iofd;
 | 
				
			||||||
	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 mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
@@ -22,6 +24,30 @@ struct mgcp_client {
 | 
				
			|||||||
	bool conn_up;
 | 
						bool conn_up;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_response_head {
 | 
				
			||||||
 | 
						int response_code;
 | 
				
			||||||
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
 | 
						char comment[MGCP_COMMENT_MAXLEN];
 | 
				
			||||||
 | 
						char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
				
			||||||
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						uint8_t x_osmo_osmux_cid;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_response {
 | 
				
			||||||
 | 
						char *body;
 | 
				
			||||||
 | 
						struct mgcp_response_head head;
 | 
				
			||||||
 | 
						uint16_t audio_port;
 | 
				
			||||||
 | 
						char audio_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Invoked when an MGCP response is received or sending failed.  When the
 | 
				
			||||||
 | 
					 * response is passed as NULL, this indicates failure during transmission. */
 | 
				
			||||||
 | 
					typedef void (*mgcp_response_cb_t)(struct mgcp_response *response, void *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending {
 | 
					struct mgcp_response_pending {
 | 
				
			||||||
	struct llist_head entry;
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -37,3 +63,41 @@ struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			|||||||
					mgcp_trans_id_t trans_id,
 | 
										mgcp_trans_id_t trans_id,
 | 
				
			||||||
					mgcp_response_cb_t response_cb,
 | 
										mgcp_response_cb_t response_cb,
 | 
				
			||||||
					void *priv);
 | 
										void *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_ENDPOINT	0x0001
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CALL_ID	0x0002
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CONN_ID	0x0004
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_msg {
 | 
				
			||||||
 | 
						enum mgcp_verb verb;
 | 
				
			||||||
 | 
						/* See MGCP_MSG_PRESENCE_* constants */
 | 
				
			||||||
 | 
						uint32_t presence;
 | 
				
			||||||
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						unsigned int call_id;
 | 
				
			||||||
 | 
						char *conn_id;
 | 
				
			||||||
 | 
						uint16_t audio_port;
 | 
				
			||||||
 | 
						char *audio_ip;
 | 
				
			||||||
 | 
						enum mgcp_connection_mode conn_mode;
 | 
				
			||||||
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						int x_osmo_osmux_cid; /* -1 is wildcard */
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_response_parse_params(struct mgcp_response *r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			||||||
 | 
							   mgcp_response_cb_t response_cb, void *priv);
 | 
				
			||||||
 | 
					int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
 | 
				
			||||||
 | 
					mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@ AM_LDFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# 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=14:1:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -302,7 +302,7 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
 | 
				
			|||||||
	char *pt_str;
 | 
						char *pt_str;
 | 
				
			||||||
	char *pt_end;
 | 
						char *pt_end;
 | 
				
			||||||
	unsigned long int pt;
 | 
						unsigned long int pt;
 | 
				
			||||||
	unsigned int count = 0;
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Extract port information */
 | 
						/* Extract port information */
 | 
				
			||||||
@@ -316,40 +316,58 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
 | 
				
			|||||||
	if (!line)
 | 
						if (!line)
 | 
				
			||||||
		goto exit;
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear any previous entries before writing over r->ptmap */
 | 
				
			||||||
 | 
						r->ptmap_len = 0;
 | 
				
			||||||
 | 
						/* Keep a local ptmap_len to show only the full list after parsing succeeded in whole. */
 | 
				
			||||||
 | 
						ptmap_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pt_str = strtok(line, " ");
 | 
						pt_str = strtok(line, " ");
 | 
				
			||||||
	while (1) {
 | 
						while (1) {
 | 
				
			||||||
		/* Do not allow excessive payload types */
 | 
					 | 
				
			||||||
		if (count > ARRAY_SIZE(r->codecs))
 | 
					 | 
				
			||||||
			goto response_parse_failure_pt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pt_str = strtok(NULL, " ");
 | 
							pt_str = strtok(NULL, " ");
 | 
				
			||||||
		if (!pt_str)
 | 
							if (!pt_str)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		errno = 0;
 | 
							errno = 0;
 | 
				
			||||||
		pt = strtoul(pt_str, &pt_end, 0);
 | 
							pt = strtoul(pt_str, &pt_end, 0);
 | 
				
			||||||
		if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
 | 
							if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
 | 
				
			||||||
		    pt_str == pt_end)
 | 
							    pt_str == pt_end) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR, "SDP: cannot parse payload type number from '%s'\n", pt_str);
 | 
				
			||||||
			goto response_parse_failure_pt;
 | 
								goto response_parse_failure_pt;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
 | 
							/* PT is 7 bit field, higher values not allowed */
 | 
				
			||||||
 | 
							if (pt >> 7) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR, "SDP: payload type number out of range: %lu > 127\n", pt);
 | 
				
			||||||
			goto response_parse_failure_pt;
 | 
								goto response_parse_failure_pt;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Do not allow duplicate payload types */
 | 
							/* Do not allow duplicate payload types */
 | 
				
			||||||
		for (i = 0; i < count; i++)
 | 
							for (i = 0; i < ptmap_len; i++) {
 | 
				
			||||||
			if (r->codecs[i] == pt)
 | 
								if (r->ptmap[i].pt == pt) {
 | 
				
			||||||
 | 
									LOGP(DLMGCP, LOGL_ERROR, "SDP: payload type number %lu listed twice\n", pt);
 | 
				
			||||||
				goto response_parse_failure_pt;
 | 
									goto response_parse_failure_pt;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Note: The payload type we store may not necessarly match
 | 
							/* Do not allow excessive payload types */
 | 
				
			||||||
		 * the codec types we have defined in enum mgcp_codecs. To
 | 
							if (ptmap_len >= ARRAY_SIZE(r->ptmap)) {
 | 
				
			||||||
		 * ensure that the end result only contains codec types which
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		 * match enum mgcp_codecs, we will go through afterwards and
 | 
								     "SDP: can parse only up to %zu payload type numbers\n", ARRAY_SIZE(r->ptmap));
 | 
				
			||||||
		 * remap the affected entries with the inrofmation we learn
 | 
								goto response_parse_failure_pt;
 | 
				
			||||||
		 * from rtpmap */
 | 
							}
 | 
				
			||||||
		r->codecs[count] = pt;
 | 
					
 | 
				
			||||||
		count++;
 | 
							/* Some payload type numbers imply a specific codec. For those, using the PT number as enum mgcp_codecs
 | 
				
			||||||
 | 
							 * yields the correct result. If no more specific information on the codec follows in "a=rtpmap:N"
 | 
				
			||||||
 | 
							 * lines, then this default number takes over. This only applies for PT below the dynamic range (<96). */
 | 
				
			||||||
 | 
							if (pt < 96)
 | 
				
			||||||
 | 
								r->ptmap[ptmap_len].codec = pt;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								r->ptmap[ptmap_len].codec = -1;
 | 
				
			||||||
 | 
							r->ptmap[ptmap_len].pt = pt;
 | 
				
			||||||
 | 
							ptmap_len++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r->codecs_len = count;
 | 
						/* Parsing succeeded, publish all entries. */
 | 
				
			||||||
 | 
						r->ptmap_len = ptmap_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -365,10 +383,11 @@ response_parse_failure_pt:
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Parse a line like "m=audio 16002 RTP/AVP 98", extract port and payload types */
 | 
					/* Parse an 'a=...' parameter */
 | 
				
			||||||
static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *line)
 | 
					static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
	char codec_resp[64];
 | 
						char codec_resp[64];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -387,18 +406,39 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
 | 
				
			|||||||
			     "Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
								     "Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
 | 
					 | 
				
			||||||
			return -ENOSPC;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rc = map_str_to_codec(codec_resp);
 | 
							rc = map_str_to_codec(codec_resp);
 | 
				
			||||||
		if (rc < 0) {
 | 
							if (rc < 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
								     "Failed to parse SDP parameter, can't parse codec in rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		r->ptmap[r->ptmap_len].pt = pt;
 | 
					
 | 
				
			||||||
		r->ptmap[r->ptmap_len].codec = rc;
 | 
							/* Earlier, a line like "m=audio 16002 RTP/AVP 98 112 3" established the desired order of payloads, now
 | 
				
			||||||
 | 
							 * enrich it with actual codec information provided by "a=rtpmap:..." entries.
 | 
				
			||||||
 | 
							 * For each, find the entry with the right pt number and add the info there. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (i = 0; i < r->ptmap_len; i++) {
 | 
				
			||||||
 | 
								if (r->ptmap[i].pt != pt)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								r->ptmap[i].codec = rc;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* No entry was found. This is an error in the MGCP protocol, but let's just add another entry
 | 
				
			||||||
 | 
							 * anyway, to not make it look like it was never there. */
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "error in MGCP message: 'a=rtpmap:%u' has no matching entry in 'm=audio ... %u'\n",
 | 
				
			||||||
 | 
							     pt, pt);
 | 
				
			||||||
 | 
							if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "cannot parse all codecs: can only store up to %zu rtpmap entries.\n",
 | 
				
			||||||
 | 
								     ARRAY_SIZE(r->ptmap));
 | 
				
			||||||
 | 
								return -ENOSPC;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							r->ptmap[r->ptmap_len] = (struct ptmap){
 | 
				
			||||||
 | 
								.pt = pt,
 | 
				
			||||||
 | 
								.codec = rc,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		r->ptmap_len++;
 | 
							r->ptmap_len++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -508,7 +548,6 @@ int mgcp_response_parse_params(struct mgcp_response *r)
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	char *data;
 | 
						char *data;
 | 
				
			||||||
	char *data_ptr;
 | 
						char *data_ptr;
 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Since this functions performs a destructive parsing, we create a
 | 
						/* Since this functions performs a destructive parsing, we create a
 | 
				
			||||||
	 * local copy of the body data */
 | 
						 * local copy of the body data */
 | 
				
			||||||
@@ -553,10 +592,6 @@ int mgcp_response_parse_params(struct mgcp_response *r)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* See also note in mgcp_parse_audio_port_pt() */
 | 
					 | 
				
			||||||
	for (i = 0; i < r->codecs_len; i++)
 | 
					 | 
				
			||||||
	        r->codecs[i] =  map_pt_to_codec(r->ptmap, r->ptmap_len, r->codecs[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = 0;
 | 
						rc = 0;
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
	talloc_free(data);
 | 
						talloc_free(data);
 | 
				
			||||||
@@ -693,7 +728,7 @@ static struct mgcp_response_pending *mgcp_client_response_pending_get(
 | 
				
			|||||||
/* Feed an MGCP message into the receive processing.
 | 
					/* Feed an MGCP message into the receive processing.
 | 
				
			||||||
 * Parse the head and call any callback registered for the transaction id found
 | 
					 * Parse the head and call any callback registered for the transaction id found
 | 
				
			||||||
 * in the MGCP message. This is normally called directly from the internal
 | 
					 * in the MGCP message. This is normally called directly from the internal
 | 
				
			||||||
 * mgcp_do_read that reads from the socket connected to the MGCP gateway. This
 | 
					 * mgcp_read_cb that reads from the socket connected to the MGCP gateway. This
 | 
				
			||||||
 * function is published mainly to be able to feed data from the test suite.
 | 
					 * function is published mainly to be able to feed data from the test suite.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
 | 
					int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
 | 
				
			||||||
@@ -746,54 +781,58 @@ error:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mgcp_do_read(struct osmo_fd *fd)
 | 
					static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client *mgcp = fd->data;
 | 
						struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
 | 
						if (res <= 0) {
 | 
				
			||||||
	if (!msg) {
 | 
							char errbuf[128] = "";
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to allocate MGCP message.\n");
 | 
							strerror_r(-res, errbuf, sizeof(errbuf));
 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = read(fd->fd, msg->data, 4096 - 128);
 | 
					 | 
				
			||||||
	if (ret <= 0) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
 | 
				
			||||||
		     osmo_sock_get_name2(fd->fd), errno, strerror(errno));
 | 
								osmo_iofd_get_name(iofd), res, errbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg->l2h = msgb_put(msg, ret);
 | 
						msg->l2h = msg->head;
 | 
				
			||||||
	ret = mgcp_client_rx(mgcp, msg);
 | 
						mgcp_client_rx(mgcp, msg);
 | 
				
			||||||
	talloc_free(msg);
 | 
						talloc_free(msg);
 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
 | 
					static int mgcp_do_write(struct mgcp_client *mgcp, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	struct mgcp_client *mgcp = fd->data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
 | 
						LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
 | 
				
			||||||
		osmo_sock_get_name2(fd->fd), msg->len,
 | 
							osmo_iofd_get_name(mgcp->iofd), msg->len,
 | 
				
			||||||
		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 = osmo_iofd_write_msgb(mgcp->iofd, msg);
 | 
				
			||||||
	if (OSMO_UNLIKELY(ret != msg->len))
 | 
						if (ret < 0)
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
							msgb_free(msg);
 | 
				
			||||||
			osmo_sock_get_name2(fd->fd), errno, strerror(errno),
 | 
					 | 
				
			||||||
			msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Re-arm the keepalive Tx timer: */
 | 
						/* Re-arm the keepalive Tx timer: */
 | 
				
			||||||
	if (mgcp->actual.keepalive.req_interval_sec > 0)
 | 
						if (mgcp->actual.keepalive.req_interval_sec > 0)
 | 
				
			||||||
		osmo_timer_schedule(&mgcp->keepalive_tx_timer, 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 void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp = osmo_iofd_get_data(iofd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (OSMO_UNLIKELY(res != msg->len)) {
 | 
				
			||||||
 | 
							char errbuf[128] = "";
 | 
				
			||||||
 | 
							strerror_r(-res, errbuf, sizeof(errbuf));
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
				
			||||||
 | 
								osmo_iofd_get_name(mgcp->iofd), res, errbuf,
 | 
				
			||||||
 | 
								msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
 | 
					static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
						static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
@@ -825,6 +864,10 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
						osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
				
			||||||
	msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
						msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
				
			||||||
 | 
						if (!msgb_dlcx) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
						mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -838,6 +881,10 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname)
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
	OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
 | 
						OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname);
 | 
				
			||||||
	msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
 | 
						msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep);
 | 
				
			||||||
 | 
						if (!msgb_auep) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
 | 
						mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -905,11 +952,6 @@ 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));
 | 
						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_tx_timer, mgcp_client_keepalive_tx_timer_cb, mgcp);
 | 
				
			||||||
	osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
 | 
						osmo_timer_setup(&mgcp->keepalive_rx_timer, mgcp_client_keepalive_rx_timer_cb, mgcp);
 | 
				
			||||||
@@ -917,6 +959,11 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	return mgcp;
 | 
						return mgcp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_io_ops mgcp_clnt_ioops = {
 | 
				
			||||||
 | 
						.read_cb = mgcp_read_cb,
 | 
				
			||||||
 | 
						.write_cb = mgcp_write_cb,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! 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. */
 | 
				
			||||||
@@ -932,19 +979,28 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_sock_init2_ofd(&mgcp->wq.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
						rc = osmo_sock_init2(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) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_FATAL,
 | 
							LOGPMGW(mgcp, LOGL_FATAL,
 | 
				
			||||||
		     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
							     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
				
			||||||
		     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
							     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
				
			||||||
		     mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
 | 
							     mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
 | 
				
			||||||
		     strerror(errno));
 | 
							     strerror(errno));
 | 
				
			||||||
		goto error_close_fd;
 | 
							goto error_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(mgcp->wq.bfd.fd));
 | 
						mgcp->iofd = osmo_iofd_setup(mgcp, rc, osmo_sock_get_name2(rc), OSMO_IO_FD_MODE_READ_WRITE,
 | 
				
			||||||
 | 
									     &mgcp_clnt_ioops, mgcp);
 | 
				
			||||||
 | 
						if (!mgcp->iofd)
 | 
				
			||||||
 | 
							goto error_close_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_iofd_get_name(mgcp->iofd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_iofd_register(mgcp->iofd, -1);
 | 
				
			||||||
 | 
						osmo_iofd_set_alloc_info(mgcp->iofd, 4096, 128);
 | 
				
			||||||
 | 
						osmo_iofd_set_txqueue_max_length(mgcp->iofd, 1024);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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. */
 | 
				
			||||||
@@ -970,9 +1026,10 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		osmo_timer_schedule(&mgcp->keepalive_rx_timer, 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(rc);
 | 
				
			||||||
	mgcp->wq.bfd.fd = -1;
 | 
					error_free:
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -989,8 +1046,6 @@ int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			|||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
					void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mgcp) {
 | 
						if (!mgcp) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
 | 
							LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -1001,13 +1056,10 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
				
			|||||||
	osmo_timer_del(&mgcp->keepalive_tx_timer);
 | 
						osmo_timer_del(&mgcp->keepalive_tx_timer);
 | 
				
			||||||
	mgcp->conn_up = false;
 | 
						mgcp->conn_up = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wq = &mgcp->wq;
 | 
						osmo_iofd_txqueue_clear(mgcp->iofd);
 | 
				
			||||||
	osmo_wqueue_clear(wq);
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd));
 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
						osmo_iofd_free(mgcp->iofd);
 | 
				
			||||||
	if (osmo_fd_is_registered(&wq->bfd))
 | 
						mgcp->iofd = NULL;
 | 
				
			||||||
		osmo_fd_unregister(&wq->bfd);
 | 
					 | 
				
			||||||
	close(wq->bfd.fd);
 | 
					 | 
				
			||||||
	wq->bfd.fd = -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get the IP-Aaddress of the associated MGW as string.
 | 
					/*! Get the IP-Aaddress of the associated MGW as string.
 | 
				
			||||||
@@ -1161,10 +1213,9 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
		goto mgcp_tx_error;
 | 
							goto mgcp_tx_error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
 | 
						rc = mgcp_do_write(mgcp, msg);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
 | 
							LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		goto mgcp_tx_error;
 | 
							goto mgcp_tx_error;
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
 | 
							LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
 | 
				
			||||||
@@ -1233,7 +1284,6 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	const char *codec;
 | 
						const char *codec;
 | 
				
			||||||
	unsigned int pt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
					#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
				
			||||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
							if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
				
			||||||
@@ -1247,11 +1297,10 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	if (mgcp_msg->ptime)
 | 
						if (mgcp_msg->ptime)
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
 | 
							MSGB_PRINTF_OR_RET(" p:%u,", mgcp_msg->ptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->codecs_len) {
 | 
						if (mgcp_msg->ptmap_len) {
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" a:");
 | 
							MSGB_PRINTF_OR_RET(" a:");
 | 
				
			||||||
		for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
							for (i = 0; i < mgcp_msg->ptmap_len; i++) {
 | 
				
			||||||
			pt = mgcp_msg->codecs[i];
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
 | 
				
			||||||
			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! */
 | 
				
			||||||
@@ -1259,7 +1308,7 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
 | 
								MSGB_PRINTF_OR_RET("%s", extract_codec_name(codec));
 | 
				
			||||||
			if (i < mgcp_msg->codecs_len - 1)
 | 
								if (i < mgcp_msg->ptmap_len - 1)
 | 
				
			||||||
				MSGB_PRINTF_OR_RET(";");
 | 
									MSGB_PRINTF_OR_RET(";");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(",");
 | 
							MSGB_PRINTF_OR_RET(",");
 | 
				
			||||||
@@ -1271,6 +1320,36 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
#undef MSGB_PRINTF_OR_RET
 | 
					#undef MSGB_PRINTF_OR_RET
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Helper function to obtain local IP address used in MGCP towards MGW,
 | 
				
			||||||
 | 
					 * in string format, to fill the SDP "Origin" ("o=") field.
 | 
				
			||||||
 | 
					 * return 0 on success, negative on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Try to get the socket local IP address if available: */
 | 
				
			||||||
 | 
						if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) {
 | 
				
			||||||
 | 
							if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							/* else: continue below */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If MGCP local address was explicitly specified in config, use it: */
 | 
				
			||||||
 | 
						if (mgcp->actual.local_addr) {
 | 
				
			||||||
 | 
							osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Guess our local address based on system routing towards MGW: */
 | 
				
			||||||
 | 
						OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN);
 | 
				
			||||||
 | 
						if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n");
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1279,6 +1358,8 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
	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;
 | 
				
			||||||
 | 
						uint16_t audio_port;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
					#define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \
 | 
				
			||||||
		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
							if (msgb_printf(msg, FMT, ##ARGS) != 0) { \
 | 
				
			||||||
@@ -1294,17 +1375,12 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
	MSGB_PRINTF_OR_RET("v=0\r\n");
 | 
						MSGB_PRINTF_OR_RET("v=0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Determine local IP-Address */
 | 
						/* Determine local IP-Address */
 | 
				
			||||||
	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
						rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip));
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
						if (rc < 0)
 | 
				
			||||||
			"Could not determine local IP-Address!\n");
 | 
							return rc;
 | 
				
			||||||
		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)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
					 | 
				
			||||||
	if (audio_ip_family == AF_UNSPEC)
 | 
					 | 
				
			||||||
		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,
 | 
						MSGB_PRINTF_OR_RET("o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
				
			||||||
@@ -1314,41 +1390,47 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
	/* Add session name (none) */
 | 
						/* Add session name (none) */
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("s=-\r\n");
 | 
						MSGB_PRINTF_OR_RET("s=-\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add RTP address and port */
 | 
						/* Add RTP address */
 | 
				
			||||||
	if (mgcp_msg->audio_port == 0) {
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
							audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
				
			||||||
			"Invalid port number, can not generate MGCP message\n");
 | 
							if (audio_ip_family == AF_UNSPEC)
 | 
				
			||||||
		msgb_free(msg);
 | 
								return -EINVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							if (strlen(mgcp_msg->audio_ip) <= 0) {
 | 
				
			||||||
 | 
								LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
 | 
									"Empty ip address, can not generate MGCP message\n");
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							MSGB_PRINTF_OR_RET("c=IN IP%c %s\r\n",
 | 
				
			||||||
 | 
									   audio_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
 | 
									   mgcp_msg->audio_ip);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strlen(mgcp_msg->audio_ip) <= 0) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR,
 | 
					 | 
				
			||||||
			"Empty ip address, can not generate MGCP message\n");
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	MSGB_PRINTF_OR_RET("c=IN IP%c %s\r\n",
 | 
					 | 
				
			||||||
			  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
					 | 
				
			||||||
			  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");
 | 
						MSGB_PRINTF_OR_RET("t=0 0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", mgcp_msg->audio_port);
 | 
						/* Add RTP address port and codecs */
 | 
				
			||||||
	for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
						audio_port = 0;
 | 
				
			||||||
		pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
						if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT)) {
 | 
				
			||||||
		MSGB_PRINTF_OR_RET(" %u", pt);
 | 
							audio_port = mgcp_msg->audio_port;
 | 
				
			||||||
 | 
							if (!audio_port) {
 | 
				
			||||||
 | 
								LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
 | 
									"Invalid port number, can not generate MGCP message\n");
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						MSGB_PRINTF_OR_RET("m=audio %u RTP/AVP", audio_port);
 | 
				
			||||||
 | 
						for (i = 0; i < mgcp_msg->ptmap_len; i++)
 | 
				
			||||||
 | 
							MSGB_PRINTF_OR_RET(" %u", mgcp_msg->ptmap[i].pt);
 | 
				
			||||||
	MSGB_PRINTF_OR_RET("\r\n");
 | 
						MSGB_PRINTF_OR_RET("\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add optional codec parameters (fmtp) */
 | 
						/* Add optional codec parameters (fmtp) */
 | 
				
			||||||
	if (mgcp_msg->param_present) {
 | 
						if (mgcp_msg->param_present) {
 | 
				
			||||||
		for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
							for (i = 0; i < mgcp_msg->ptmap_len; i++) {
 | 
				
			||||||
			/* The following is only applicable for AMR */
 | 
								/* The following is only applicable for AMR */
 | 
				
			||||||
			if (mgcp_msg->codecs[i] != CODEC_AMR_8000_1 && mgcp_msg->codecs[i] != CODEC_AMRWB_16000_1)
 | 
								if (mgcp_msg->ptmap[i].codec != CODEC_AMR_8000_1
 | 
				
			||||||
				   continue;
 | 
								    && mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1)
 | 
				
			||||||
			pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
									continue;
 | 
				
			||||||
 | 
								pt = mgcp_msg->ptmap[i].pt;
 | 
				
			||||||
			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);
 | 
									MSGB_PRINTF_OR_RET("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)
 | 
				
			||||||
@@ -1356,14 +1438,14 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
						for (i = 0; i < mgcp_msg->ptmap_len; i++) {
 | 
				
			||||||
		pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
							pt = mgcp_msg->ptmap[i].pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Note: Only dynamic payload type from the range 96-127
 | 
							/* Note: Only dynamic payload type from the range 96-127
 | 
				
			||||||
		 * require to be explained further via rtpmap. All others
 | 
							 * require to be explained further via rtpmap. All others
 | 
				
			||||||
		 * are implcitly definedby the number in m=audio */
 | 
							 * are implcitly definedby the number in m=audio */
 | 
				
			||||||
		if (pt >= 96 && pt <= 127) {
 | 
							if (pt >= 96 && pt <= 127) {
 | 
				
			||||||
			codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->codecs[i]);
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->ptmap[i].codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
@@ -1470,10 +1552,10 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
		MSGB_PRINTF_OR_RET("I: %s\r\n", mgcp_msg->conn_id);
 | 
							MSGB_PRINTF_OR_RET("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 or Port is specified,
 | 
				
			||||||
	 * 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)
 | 
				
			||||||
		use_sdp = true;
 | 
							use_sdp = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add local connection options (LCO) */
 | 
						/* Add local connection options (LCO) */
 | 
				
			||||||
@@ -1571,3 +1653,20 @@ const char *mgcp_client_name(const struct mgcp_client *mgcp)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		return mgcp_client_endpoint_domain(mgcp);
 | 
							return mgcp_client_endpoint_domain(mgcp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Return typical cmp result, comparing a to b.
 | 
				
			||||||
 | 
					 * Return 0 if a == b, -1 if a < b, 1 if a > b; comparing all members of ptmap in turn. */
 | 
				
			||||||
 | 
					int ptmap_cmp(const struct ptmap *a, const struct ptmap *b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						if (a == b)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						if (!a)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						if (!b)
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						rc = OSMO_CMP(a->codec, b->codec);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						return OSMO_CMP(a->pt, b->pt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -533,10 +533,42 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			|||||||
	       mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
 | 
						       mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
 | 
				
			||||||
	       ci->notify.fi ? "" : " (not sending a notification)");
 | 
						       ci->notify.fi ? "" : " (not sending a notification)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Below ordering is a delicate decision:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We want to
 | 
				
			||||||
 | 
						 * - emit the resulting event to ci->notify.fi,
 | 
				
			||||||
 | 
						 * - check whether we want to tx the next pending MGCP message.
 | 
				
			||||||
 | 
						 * Both these steps may terminate (=deallocate) the ep.
 | 
				
			||||||
 | 
						 * So whichever one goes first may cause a use-after-free in the other.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * When dispatching the FSM event, we don't get an rc indicating dealloc of the FSM -- it may deallocate and we
 | 
				
			||||||
 | 
						 * cannot tell. The common mechanism for that is osmo_fsm_set_dealloc_ctx(OTC_SELECT) and query the still
 | 
				
			||||||
 | 
						 * allocated FSM state after termination (here we would check 'if (ci->ep != NULL)'), but we cannot assume the
 | 
				
			||||||
 | 
						 * caller has actually set up an osmo_fsm_set_dealloc_ctx(). At time of writing, e.g. osmo-hnbgw does not use
 | 
				
			||||||
 | 
						 * it.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * In osmo_mgcpc_ep_fsm_check_state_chg_after_response(), we do get an rc: false means FSM has terminated.
 | 
				
			||||||
 | 
						 * On termination, the ep emits a term event to the FSM's parent.
 | 
				
			||||||
 | 
						 * That may cause the notify.fi to be terminated in turn, depending on how the caller set things up.
 | 
				
			||||||
 | 
						 * So: we cannot store notify.fi before, then call osmo_mgcpc_ep_fsm_check_state_chg_after_response(), and then
 | 
				
			||||||
 | 
						 * emit the event, because notify.fi may have deallocated. We cannot look up whether
 | 
				
			||||||
 | 
						 * osmo_mgcpc_ep_cancel_notify() has been called, because ci may have deallocated along with ci->ep.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We have to skip emitting below success event in case the ep is now terminated.
 | 
				
			||||||
 | 
						 * - It may be the final DLCX OK: not a problem, osmo_mgcpc_ep_ci_dlcx() has no notify args on purpose, so we do
 | 
				
			||||||
 | 
						 *   make all callers not set a notify event for DLCX by design. notify.fi should always be NULL when the final
 | 
				
			||||||
 | 
						 *   DLCX OK terminates the local endpoint state.
 | 
				
			||||||
 | 
						 * - It may also be sudden termination due to a bad problem, in which case we shouldn't emit success.
 | 
				
			||||||
 | 
						 *   The osmo_fsm_inst.parent_term_event should suffice as feedback to the caller.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi) == false) {
 | 
				
			||||||
 | 
							/* false means, the ci->ep has been terminated. */
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ci->notify.fi)
 | 
						if (ci->notify.fi)
 | 
				
			||||||
		osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
 | 
							osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
 | 
					/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
 | 
				
			||||||
@@ -686,11 +718,11 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			|||||||
	osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
 | 
						osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
 | 
				
			||||||
	*ci = cleared_ci;
 | 
						*ci = cleared_ci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (verb_info)
 | 
						if (verb_info)
 | 
				
			||||||
		ci->verb_info = *verb_info;
 | 
							ci->verb_info = *verb_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ep->endpoint[0]) {
 | 
						if (ep->endpoint[0]) {
 | 
				
			||||||
		if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
 | 
							if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
 | 
				
			||||||
			LOG_CI(ci, LOGL_ERROR,
 | 
								LOG_CI(ci, LOGL_ERROR,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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_fsm.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_fsm.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/fsm.h>
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
@@ -114,12 +115,10 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
 | 
				
			|||||||
		.call_id = info->call_id,
 | 
							.call_id = info->call_id,
 | 
				
			||||||
		.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
							.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
				
			||||||
		.ptime = info->ptime,
 | 
							.ptime = info->ptime,
 | 
				
			||||||
		.codecs_len = info->codecs_len,
 | 
					 | 
				
			||||||
		.ptmap_len = info->ptmap_len,
 | 
							.ptmap_len = info->ptmap_len,
 | 
				
			||||||
		.param_present = info->param_present
 | 
							.param_present = info->param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
 | 
					 | 
				
			||||||
	memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
						memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
				
			||||||
	memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
 | 
						memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,10 +135,19 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
					static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT;
 | 
						bool ip_is_set = info->addr[0] != '\0' &&
 | 
				
			||||||
	mgcp_msg->audio_ip = info->addr;
 | 
								 strncmp(info->addr, "::", sizeof(info->addr)) != 0 &&
 | 
				
			||||||
	mgcp_msg->audio_port = info->port;
 | 
								 strncmp(info->addr, "0.0.0.0", sizeof(info->addr)) != 0;
 | 
				
			||||||
	mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
						if (ip_is_set) {
 | 
				
			||||||
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP;
 | 
				
			||||||
 | 
							mgcp_msg->audio_ip = info->addr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (info->port) {
 | 
				
			||||||
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_PORT;
 | 
				
			||||||
 | 
							mgcp_msg->audio_port = info->port;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ip_is_set && info->port)
 | 
				
			||||||
 | 
							mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
 | 
					static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
 | 
				
			||||||
@@ -149,6 +157,7 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
 | 
				
			|||||||
		mgcp_msg->conn_mode = conn_mode;
 | 
							mgcp_msg->conn_mode = conn_mode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* returns message buffer containing MGXP MDCX on success, NULL on error. */
 | 
				
			||||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
					static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_msg mgcp_msg;
 | 
						struct mgcp_msg mgcp_msg;
 | 
				
			||||||
@@ -163,12 +172,10 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			|||||||
		.audio_ip = mgcp_ctx->conn_peer_local.addr,
 | 
							.audio_ip = mgcp_ctx->conn_peer_local.addr,
 | 
				
			||||||
		.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
							.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
				
			||||||
		.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
							.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
				
			||||||
		.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
 | 
					 | 
				
			||||||
		.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
 | 
							.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
 | 
				
			||||||
		.param_present = mgcp_ctx->conn_peer_local.param_present
 | 
							.param_present = mgcp_ctx->conn_peer_local.param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
 | 
					 | 
				
			||||||
	memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
						memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
				
			||||||
	memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
 | 
						memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,6 +193,7 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			|||||||
	return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
						return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* returns message buffer containing MGXP DLCX on success, NULL on error. */
 | 
				
			||||||
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
					struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_msg mgcp_msg;
 | 
						struct mgcp_msg mgcp_msg;
 | 
				
			||||||
@@ -221,13 +229,14 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			|||||||
			 mgcp_ctx->conn_peer_local.endpoint);
 | 
								 mgcp_ctx->conn_peer_local.endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
							make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
		if (mgcp_ctx->conn_peer_local.port)
 | 
							add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
			add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
					 | 
				
			||||||
		set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
							set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
							msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
 | 
							mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
 | 
				
			||||||
		mgcp_ctx->mgw_trans_pending = true;
 | 
							mgcp_ctx->mgw_trans_pending = true;
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
 | 
				
			||||||
@@ -364,13 +373,21 @@ static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			|||||||
	switch (event) {
 | 
						switch (event) {
 | 
				
			||||||
	case EV_MDCX:
 | 
						case EV_MDCX:
 | 
				
			||||||
		msg = make_mdcx_msg(mgcp_ctx);
 | 
							msg = make_mdcx_msg(mgcp_ctx);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								/* make_mdcx_msg() should already have logged the error */
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
 | 
				
			||||||
		new_state = ST_MDCX_RESP;
 | 
							new_state = ST_MDCX_RESP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case EV_DLCX:
 | 
						case EV_DLCX:
 | 
				
			||||||
		msg = make_dlcx_msg(mgcp_ctx);
 | 
							msg = make_dlcx_msg(mgcp_ctx);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								/* make_dlcx_msg() should already have logged the error */
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
 | 
				
			||||||
		new_state = ST_DLCX_RESP;
 | 
							new_state = ST_DLCX_RESP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -611,6 +628,72 @@ static struct osmo_fsm fsm_mgcp_client = {
 | 
				
			|||||||
	.log_subsys = DLMGCP,
 | 
						.log_subsys = DLMGCP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
 | 
				
			||||||
 | 
					 * that has codecs[] set, apply it to ptmap[] instead. */
 | 
				
			||||||
 | 
					static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!conn_peer->codecs_len)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Before dropping codecs[], codecs[] would indicate the order in which the codecs should appear in SDP. ptmap[]
 | 
				
			||||||
 | 
						 * would indicate payload type numbers when not using a default payload type number (may omit entries).
 | 
				
			||||||
 | 
						 * Now, ptmap[] just indicates both at the same time; codecs[] should be empty, and ptmap[] lists all codecs.
 | 
				
			||||||
 | 
						 * So if any codecs[] are present, recreate ptmap[] in the order of codecs[]. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptmap_len = 0;
 | 
				
			||||||
 | 
						for (int i = 0; i < conn_peer->codecs_len; i++) {
 | 
				
			||||||
 | 
							enum mgcp_codecs codec = conn_peer->codecs[i];
 | 
				
			||||||
 | 
							struct ptmap *found = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Look up whether a specific pt was indicated for this codec */
 | 
				
			||||||
 | 
							for (int p = 0; p < conn_peer->ptmap_len; p++) {
 | 
				
			||||||
 | 
								if (conn_peer->ptmap[p].codec != codec)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								found = &conn_peer->ptmap[p];
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (found) {
 | 
				
			||||||
 | 
								ptmap[ptmap_len] = *found;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ptmap[ptmap_len] = (struct ptmap){
 | 
				
			||||||
 | 
									.codec = codec,
 | 
				
			||||||
 | 
									/* some enum mgcp_codecs correspond to their standard PT nr, so for compat: */
 | 
				
			||||||
 | 
									.pt = codec,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ptmap_len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Are there any entries in the old ptmap that were omitted by codecs[]? */
 | 
				
			||||||
 | 
						for (int p = 0; p < conn_peer->ptmap_len; p++) {
 | 
				
			||||||
 | 
							bool exists = false;
 | 
				
			||||||
 | 
							for (int i = 0; i < ptmap_len; i++) {
 | 
				
			||||||
 | 
								if (ptmap_cmp(&ptmap[i], &conn_peer->ptmap[p]))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								exists = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (exists)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ptmap_len >= ARRAY_SIZE(ptmap))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Not present yet, add it to the end */
 | 
				
			||||||
 | 
							ptmap[ptmap_len] = conn_peer->ptmap[p];
 | 
				
			||||||
 | 
							ptmap_len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use the new ptmap[], and clear out legacy codecs[]. */
 | 
				
			||||||
 | 
						memcpy(conn_peer->ptmap, ptmap, sizeof(conn_peer->ptmap));
 | 
				
			||||||
 | 
						conn_peer->ptmap_len = ptmap_len;
 | 
				
			||||||
 | 
						conn_peer->codecs_len = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate FSM, and create a new connection on the MGW.
 | 
					/*! allocate FSM, and create a new connection on the MGW.
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \param[in] parent_fi Parent FSM instance.
 | 
					 *  \param[in] parent_fi Parent FSM instance.
 | 
				
			||||||
@@ -625,6 +708,7 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
 | 
				
			|||||||
	struct osmo_fsm_inst *fi;
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
	struct in6_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_peer_compat(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(parent_fi);
 | 
						OSMO_ASSERT(parent_fi);
 | 
				
			||||||
	OSMO_ASSERT(mgcp);
 | 
						OSMO_ASSERT(mgcp);
 | 
				
			||||||
@@ -664,6 +748,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
	struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
						struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
				
			||||||
	struct in6_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_peer_compat(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(mgcp_ctx);
 | 
						OSMO_ASSERT(mgcp_ctx);
 | 
				
			||||||
	OSMO_ASSERT(conn_peer);
 | 
						OSMO_ASSERT(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -322,7 +322,7 @@ DEFUN(cfg_mgw_mgw_keepalive_req_interval,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* If client already exists, apply the change immediately if possible: */
 | 
						/* If client already exists, apply the change immediately if possible: */
 | 
				
			||||||
	mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
 | 
						mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
 | 
				
			||||||
	if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
 | 
						if (mgcp->iofd) { /* UDP MGCP socket connected */
 | 
				
			||||||
		if (mgcp->actual.keepalive.req_interval_sec > 0) {
 | 
							if (mgcp->actual.keepalive.req_interval_sec > 0) {
 | 
				
			||||||
			/* Re-schedule: */
 | 
								/* Re-schedule: */
 | 
				
			||||||
			osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
								osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
				
			||||||
@@ -375,7 +375,7 @@ DEFUN(cfg_mgw_mgw_keepalive_timeout,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* If client already exists, apply the change immediately if possible: */
 | 
						/* If client already exists, apply the change immediately if possible: */
 | 
				
			||||||
	mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
 | 
						mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
 | 
				
			||||||
	if (mgcp->wq.bfd.fd != -1) { /* UDP MGCP socket connected */
 | 
						if (mgcp->iofd) { /* UDP MGCP socket connected */
 | 
				
			||||||
		if (mgcp->actual.keepalive.timeout_sec > 0) {
 | 
							if (mgcp->actual.keepalive.timeout_sec > 0) {
 | 
				
			||||||
			/* Re-schedule: */
 | 
								/* Re-schedule: */
 | 
				
			||||||
			osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
								osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
				
			||||||
@@ -680,7 +680,7 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
 | 
				
			|||||||
		const struct mgcp_client *cli = pool_member->client;
 | 
							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 link:     %s,%s%s",
 | 
				
			||||||
			cli && cli->wq.bfd.fd != -1 ? "connected" : "disconnected",
 | 
								cli && cli->iofd ? "connected" : "disconnected",
 | 
				
			||||||
			cli && cli->conn_up ?
 | 
								cli && cli->conn_up ?
 | 
				
			||||||
				((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
 | 
									((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
 | 
				
			||||||
				"DOWN",
 | 
									"DOWN",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
	mgcp_trunk.c \
 | 
						mgcp_trunk.c \
 | 
				
			||||||
	mgcp_ratectr.c \
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
 | 
						mgcp_rtp_end.c \
 | 
				
			||||||
	mgcp_e1.c \
 | 
						mgcp_e1.c \
 | 
				
			||||||
	mgcp_iuup.c \
 | 
						mgcp_iuup.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Helper function to dump codec information of a specified codec to a printable
 | 
					/* Helper function to dump codec information of a specified codec to a printable
 | 
				
			||||||
 * string, used by dump_codec_summary() */
 | 
					 * string, used by dump_codec_summary() */
 | 
				
			||||||
static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
					static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char str[256];
 | 
						static char str[256];
 | 
				
			||||||
	char *pt_str;
 | 
						char *pt_str;
 | 
				
			||||||
@@ -49,31 +49,25 @@ static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dump a summary of all negotiated codecs to debug log
 | 
					/*! Dump a summary of all negotiated codecs to debug log
 | 
				
			||||||
 *  \param[in] conn related rtp-connection. */
 | 
					 *  \param[in] cset related codecset.
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
					 *  \param[in] prefix_str Prefix string to print during logging.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp = &conn->end;
 | 
						if (cset->codecs_assigned == 0) {
 | 
				
			||||||
	endp = conn->conn->endp;
 | 
							LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rtp->codecs_assigned == 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
 | 
					 | 
				
			||||||
			 mgcp_conn_dump(conn->conn));
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Store parsed codec information */
 | 
						/* Store parsed codec information */
 | 
				
			||||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
		codec = &rtp->codecs[i];
 | 
							struct mgcp_rtp_codec *codec = &cset->codecs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn), i, dump_codec(codec));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (codec == rtp->codec)
 | 
							if (codec == cset->codec)
 | 
				
			||||||
			LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
 | 
								LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_DEBUG, "\n");
 | 
							LOGPC(DLMGCP, LOGL_DEBUG, "\n");
 | 
				
			||||||
@@ -81,7 +75,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initalize or reset codec information with default data. */
 | 
					/* Initalize or reset codec information with default data. */
 | 
				
			||||||
static void codec_init(struct mgcp_rtp_codec *codec)
 | 
					static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	*codec = (struct mgcp_rtp_codec){
 | 
						*codec = (struct mgcp_rtp_codec){
 | 
				
			||||||
		.payload_type = -1,
 | 
							.payload_type = -1,
 | 
				
			||||||
@@ -94,20 +88,20 @@ static void codec_init(struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void codec_free(struct mgcp_rtp_codec *codec)
 | 
					static void mgcp_codec_free(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	*codec = (struct mgcp_rtp_codec){};
 | 
						*codec = (struct mgcp_rtp_codec){};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initalize or reset codec information with default data.
 | 
					/*! Initalize or reset codec information with default data.
 | 
				
			||||||
 *  \param[out] conn related rtp-connection. */
 | 
					 *  \param[out] conn related rtp-connection. */
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
					void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < conn->end.codecs_assigned; i++)
 | 
						for (i = 0; i < cset->codecs_assigned; i++)
 | 
				
			||||||
		codec_free(&conn->end.codecs[i]);
 | 
							mgcp_codec_free(&cset->codecs[i]);
 | 
				
			||||||
	conn->end.codecs_assigned = 0;
 | 
						cset->codecs_assigned = 0;
 | 
				
			||||||
	conn->end.codec = NULL;
 | 
						cset->codec = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Add codec configuration depending on payload type and/or codec name. This
 | 
					/*! Add codec configuration depending on payload type and/or codec name. This
 | 
				
			||||||
@@ -118,23 +112,23 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
					 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
				
			||||||
 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
					 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
					int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rate;
 | 
						int rate;
 | 
				
			||||||
	int channels;
 | 
						int channels;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	unsigned int pt_offset = conn->end.codecs_assigned;
 | 
						unsigned int pt_offset = cset->codecs_assigned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The amount of codecs we can store is limited, make sure we do not
 | 
						/* The amount of codecs we can store is limited, make sure we do not
 | 
				
			||||||
	 * overrun this limit. */
 | 
						 * overrun this limit. */
 | 
				
			||||||
	if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
 | 
						if (cset->codecs_assigned >= MGCP_MAX_CODECS)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* First unused entry */
 | 
						/* First unused entry */
 | 
				
			||||||
	codec = &conn->end.codecs[conn->end.codecs_assigned];
 | 
						codec = &cset->codecs[cset->codecs_assigned];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Initalize the codec struct with some default data to begin with */
 | 
						/* Initalize the codec struct with some default data to begin with */
 | 
				
			||||||
	codec_init(codec);
 | 
						mgcp_codec_init(codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (payload_type != PTYPE_UNDEFINED) {
 | 
						if (payload_type != PTYPE_UNDEFINED) {
 | 
				
			||||||
		/* Make sure we do not get any reserved or undefined type numbers */
 | 
							/* Make sure we do not get any reserved or undefined type numbers */
 | 
				
			||||||
@@ -268,11 +262,11 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
				
			|||||||
	} else
 | 
						} else
 | 
				
			||||||
		codec->param_present = false;
 | 
							codec->param_present = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->end.codecs_assigned++;
 | 
						cset->codecs_assigned++;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	/* Make sure we leave a clean codec entry on error. */
 | 
						/* Make sure we leave a clean codec entry on error. */
 | 
				
			||||||
	codec_free(codec);
 | 
						mgcp_codec_free(codec);
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -296,7 +290,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare two codecs, all parameters must match up */
 | 
					/* Compare two codecs, all parameters must match up */
 | 
				
			||||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
 | 
						/* 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
 | 
						 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
 | 
				
			||||||
@@ -325,7 +319,7 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
 | 
					/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
 | 
				
			||||||
static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
 | 
						/* 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.
 | 
						 * translate between different payload formats as long as the encoded voice data itself does not change.
 | 
				
			||||||
@@ -354,21 +348,18 @@ iufp:
 | 
				
			|||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_end = &conn->end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
						/* 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. */
 | 
						 * the first run we will look for an exact match. */
 | 
				
			||||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
						codecs_assigned = cset->codecs_assigned;
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						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 (codecs_same(codec, &cset->codecs[i])) {
 | 
				
			||||||
			return &rtp_end->codecs[i];
 | 
								return &cset->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -377,28 +368,26 @@ struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct m
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* For a given codec, find a convertible codec in the given connection. */
 | 
					/* For a given codec, find a convertible codec in the given connection. */
 | 
				
			||||||
static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec)
 | 
					static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec_convertible = NULL;
 | 
						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
 | 
						/* 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. */
 | 
						 * the first run we will look for an exact match. */
 | 
				
			||||||
	codec_convertible = mgcp_codec_find_same(conn, codec);
 | 
						codec_convertible = mgcp_codecset_find_same(cset, codec);
 | 
				
			||||||
	if (codec_convertible)
 | 
						if (codec_convertible)
 | 
				
			||||||
		return 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
 | 
						/* 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) */
 | 
						 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
 | 
				
			||||||
	codecs_assigned = rtp_end->codecs_assigned;
 | 
						codecs_assigned = cset->codecs_assigned;
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						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_convertible(codec, &cset->codecs[i])) {
 | 
				
			||||||
			codec_convertible = &rtp_end->codecs[i];
 | 
								codec_convertible = &cset->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -408,20 +397,20 @@ static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
 | 
					/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
 | 
				
			||||||
 *  a tentative decision is made.
 | 
					 *  a tentative decision is made.
 | 
				
			||||||
 *  \param[inout] conn_src related rtp-connection.
 | 
					 *  \param[in] cset_src related codec set.
 | 
				
			||||||
 *  \param[inout] conn_dst related destination rtp-connection (NULL if not present).
 | 
					 *  \param[inout] cset_dst related destination codec set (NULL if not present).
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
 | 
					int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In case no destination connection is available (yet), or in case the destination connection exists but has
 | 
						/* 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:
 | 
						 * no codecs assigned, we are forced to make a simple tentative decision:
 | 
				
			||||||
	 * We just use the first codec of the source connection (conn_src) */
 | 
						 * We just use the first codec of the source connection (conn_src) */
 | 
				
			||||||
	OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	if (!conn_dst || conn_dst->end.codecs_assigned == 0) {
 | 
						if (!cset_dst || cset_dst->codecs_assigned == 0) {
 | 
				
			||||||
		if (conn_src->end.codecs_assigned >= 1) {
 | 
							if (cset_src->codecs_assigned >= 1) {
 | 
				
			||||||
			conn_src->end.codec = &conn_src->end.codecs[0];
 | 
								cset_src->codec = &cset_src->codecs[0];
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
@@ -430,33 +419,42 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn
 | 
				
			|||||||
	/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
 | 
						/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
 | 
				
			||||||
	 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
 | 
						 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
 | 
				
			||||||
	 * required. */
 | 
						 * required. */
 | 
				
			||||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
						for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
				
			||||||
		struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, &conn_src->end.codecs[i]);
 | 
							struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
				
			||||||
		if (codec_conn_dst) {
 | 
							struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
 | 
				
			||||||
 | 
							if (codec_cset_dst) {
 | 
				
			||||||
			/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
 | 
								/* 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. */
 | 
								 * sides. We now set this codec on both connections. */
 | 
				
			||||||
			conn_dst->end.codec = codec_conn_dst;
 | 
								cset_dst->codec = codec_cset_dst;
 | 
				
			||||||
			conn_src->end.codec = mgcp_codec_find_same(conn_src, codec_conn_dst);
 | 
								cset_src->codec = codec_cset_src;
 | 
				
			||||||
			OSMO_ASSERT(conn_src->end.codec);
 | 
					 | 
				
			||||||
			return 0;
 | 
								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
 | 
						/* 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. */
 | 
						 * to convert. */
 | 
				
			||||||
	for (i = 0; i < conn_src->end.codecs_assigned; i++) {
 | 
						for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
				
			||||||
		struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, &conn_src->end.codecs[i]);
 | 
							struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
				
			||||||
		if (codec_conn_dst) {
 | 
							struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
 | 
				
			||||||
			/* We found the a codec that we are able to convert on both sides. We now set this codec on both
 | 
							if (codec_cset_dst) {
 | 
				
			||||||
			 * connections. */
 | 
								/* We found the a codec that we can convert to. Set each side to its codec. */
 | 
				
			||||||
			conn_dst->end.codec = codec_conn_dst;
 | 
								cset_dst->codec = codec_cset_dst;
 | 
				
			||||||
			conn_src->end.codec = codec_find_convertible(conn_src, codec_conn_dst);
 | 
								cset_src->codec = codec_cset_src;
 | 
				
			||||||
			OSMO_ASSERT(conn_src->end.codec);
 | 
					 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -EINVAL;
 | 
						if (cset_dst->codecs_assigned)
 | 
				
			||||||
 | 
							cset_dst->codec = &cset_dst->codecs[0];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cset_src->codecs_assigned)
 | 
				
			||||||
 | 
							cset_src->codec = &cset_src->codecs[0];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
					/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
				
			||||||
@@ -479,38 +477,36 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
					 * \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_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr)
 | 
													const char *subtype_name, unsigned int match_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < conn->end.codecs_assigned; i++) {
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
		if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
 | 
							if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
 | 
				
			||||||
			if (match_nr) {
 | 
								if (match_nr) {
 | 
				
			||||||
				match_nr--;
 | 
									match_nr--;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return &conn->end.codecs[i];
 | 
								return &cset->codecs[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Lookup a codec that is assigned to a connection by its payload type number.
 | 
					/*! Lookup a codec that is assigned to a connection by its payload type number.
 | 
				
			||||||
 *  \param[in] conn related rtp-connection.
 | 
					 *  \param[in] cset related codec set.
 | 
				
			||||||
 *  \param[in] payload_type number of the codec to look up.
 | 
					 *  \param[in] payload_type number of the codec to look up.
 | 
				
			||||||
 *  \returns pointer to codec struct on success, NULL on failure. */
 | 
					 *  \returns pointer to codec struct on success, NULL on failure. */
 | 
				
			||||||
struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type)
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end = &conn->end;
 | 
					 | 
				
			||||||
	unsigned int codecs_assigned = rtp_end->codecs_assigned;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec = NULL;
 | 
						struct mgcp_rtp_codec *codec = NULL;
 | 
				
			||||||
	size_t i;
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
		if (payload_type == rtp_end->codecs[i].payload_type) {
 | 
							if (payload_type == cset->codecs[i].payload_type) {
 | 
				
			||||||
			codec = &rtp_end->codecs[i];
 | 
								codec = &cset->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* ensure that the generated conn_id is unique
 | 
							/* ensure that the generated conn_id is unique
 | 
				
			||||||
		 * for this endpoint */
 | 
							 * for this endpoint */
 | 
				
			||||||
		if (!mgcp_conn_get_rtp(endp, id_hex)) {
 | 
							if (!mgcp_endp_get_conn_rtp(endp, id_hex)) {
 | 
				
			||||||
			osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
 | 
								osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -88,7 +88,6 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
				
			|||||||
/* Initialize rtp connection struct with default values */
 | 
					/* Initialize rtp connection struct with default values */
 | 
				
			||||||
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
					static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
					 | 
				
			||||||
	/* FIXME: Each new rate counter group requires an unique index. At the
 | 
						/* FIXME: Each new rate counter group requires an unique index. At the
 | 
				
			||||||
	 * moment we generate this index using this counter, but perhaps there
 | 
						 * moment we generate this index using this counter, but perhaps there
 | 
				
			||||||
	 * is a more concious way to assign the indexes. */
 | 
						 * is a more concious way to assign the indexes. */
 | 
				
			||||||
@@ -106,19 +105,6 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	/* backpointer to the generic part of the connection */
 | 
						/* backpointer to the generic part of the connection */
 | 
				
			||||||
	conn->u.rtp.conn = conn;
 | 
						conn->u.rtp.conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	end->rtp.fd = -1;
 | 
					 | 
				
			||||||
	end->rtcp.fd = -1;
 | 
					 | 
				
			||||||
	memset(&end->addr, 0, sizeof(end->addr));
 | 
					 | 
				
			||||||
	end->rtcp_port = 0;
 | 
					 | 
				
			||||||
	talloc_free(end->fmtp_extra);
 | 
					 | 
				
			||||||
	end->fmtp_extra = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Set default values */
 | 
					 | 
				
			||||||
	end->frames_per_packet = 0;	/* unknown */
 | 
					 | 
				
			||||||
	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
					 | 
				
			||||||
	end->output_enabled = false;
 | 
					 | 
				
			||||||
	end->maximum_packet_time = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
						conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
				
			||||||
	if (!conn_rtp->ctrg)
 | 
						if (!conn_rtp->ctrg)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -126,9 +112,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
						mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,16 +123,15 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			|||||||
		conn_osmux_disable(conn_rtp);
 | 
							conn_osmux_disable(conn_rtp);
 | 
				
			||||||
	if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
						if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
				
			||||||
		mgcp_conn_iuup_cleanup(conn_rtp);
 | 
							mgcp_conn_iuup_cleanup(conn_rtp);
 | 
				
			||||||
	mgcp_free_rtp_port(&conn_rtp->end);
 | 
						mgcp_rtp_end_cleanup(&conn_rtp->end);
 | 
				
			||||||
	rate_ctr_group_free(conn_rtp->ctrg);
 | 
						rate_ctr_group_free(conn_rtp->ctrg);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_conn_watchdog_cb(void *data)
 | 
					void mgcp_conn_watchdog_cb(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn = data;
 | 
						struct mgcp_conn *conn = data;
 | 
				
			||||||
	LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
						LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
				
			||||||
	mgcp_conn_free(conn->endp, conn->id);
 | 
						mgcp_conn_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
				
			||||||
@@ -214,58 +197,6 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return conn;
 | 
						return conn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! find a connection by its ID.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 | 
				
			||||||
 *  \param[in] id identification number of the connection
 | 
					 | 
				
			||||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
					 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
	const char *id_upper;
 | 
					 | 
				
			||||||
	const char *conn_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!id || !*id)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Ignore leading zeros in needle */
 | 
					 | 
				
			||||||
	while (*id == '0')
 | 
					 | 
				
			||||||
		id++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
					 | 
				
			||||||
	 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
					 | 
				
			||||||
	 * we sent upper case hex in the CRCX response. */
 | 
					 | 
				
			||||||
	id_upper = osmo_str_toupper(id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
					 | 
				
			||||||
		/* Ignore leading zeros in haystack */
 | 
					 | 
				
			||||||
		for (conn_id=conn->id; *conn_id == '0'; conn_id++);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (strcmp(conn_id, id_upper) == 0)
 | 
					 | 
				
			||||||
			return conn;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! find an RTP connection by its ID.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 | 
				
			||||||
 *  \param[in] id identification number of the connection
 | 
					 | 
				
			||||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
					 | 
				
			||||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
					const char *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn = mgcp_conn_get(endp, id);
 | 
					 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
					 | 
				
			||||||
		return &conn->u.rtp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
					static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
@@ -288,21 +219,21 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
 | 
				
			|||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! free a connection by its ID.
 | 
					/*! free a connection
 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 *  \param[in] conn the conn to free. May be NULL.
 | 
				
			||||||
 *  \param[in] id identification number of the connection */
 | 
					*/
 | 
				
			||||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
					void mgcp_conn_free(struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = mgcp_conn_get(endp, id);
 | 
					 | 
				
			||||||
	if (!conn)
 | 
						if (!conn)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		aggregate_rtp_conn_stats(endp, &conn->u.rtp);
 | 
							conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		mgcp_rtp_conn_cleanup(&conn->u.rtp);
 | 
							aggregate_rtp_conn_stats(conn->endp, conn_rtp);
 | 
				
			||||||
 | 
							mgcp_rtp_conn_cleanup(conn_rtp);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* NOTE: This should never be called with an
 | 
							/* NOTE: This should never be called with an
 | 
				
			||||||
@@ -312,43 +243,40 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_timer_del(&conn->watchdog);
 | 
						osmo_timer_del(&conn->watchdog);
 | 
				
			||||||
	mgcp_endp_remove_conn(endp, conn);
 | 
						mgcp_endp_remove_conn(conn->endp, conn);
 | 
				
			||||||
	/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
						/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
				
			||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! free oldest connection in the list.
 | 
					/*! Parse connection mode.
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 *  \param[in] conn Connection whose mode is being set
 | 
				
			||||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
 | 
					 *  \param[in] mode Mode to set
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on error */
 | 
				
			||||||
 | 
					int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
						if (mode == MGCP_CONN_NONE) {
 | 
				
			||||||
 | 
							LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "missing connection mode\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						conn->mode = mode;
 | 
				
			||||||
 | 
						LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
				
			||||||
 | 
							 mgcp_cmode_name(mode), conn->mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_empty(&endp->conns))
 | 
						/* Special handling for RTP connections */
 | 
				
			||||||
		return;
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
 | 
							struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
							conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
				
			||||||
 | 
							LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
				
			||||||
 | 
								 conn_rtp->end.output_enabled);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
						/* The VTY might change the connection mode at any time, so we have
 | 
				
			||||||
	if (!conn)
 | 
						 * to hold a copy of the original connection mode */
 | 
				
			||||||
		return;
 | 
						conn->mode_orig = conn->mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_conn_free(endp, conn->id);
 | 
						return 0;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! free all connections at once.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 | 
				
			||||||
#if defined(__has_attribute)
 | 
					 | 
				
			||||||
#if __has_attribute(no_sanitize)
 | 
					 | 
				
			||||||
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Drop all items in the list, might be consecutive! */
 | 
					 | 
				
			||||||
	while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
					 | 
				
			||||||
		mgcp_conn_free(endp, conn->id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dump basic connection information to human readable string.
 | 
					/*! dump basic connection information to human readable string.
 | 
				
			||||||
@@ -358,53 +286,39 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
						static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn)
 | 
				
			||||||
		snprintf(str, sizeof(str), "(null connection)");
 | 
							return "NULL";
 | 
				
			||||||
		return str;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		switch (conn->u.rtp.type) {
 | 
							conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		case MGCP_RTP_DEFAULT:
 | 
							OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
 | 
				
			||||||
			/* Dump RTP connection */
 | 
									   conn->name,
 | 
				
			||||||
			snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
									   mgcp_conn_rtp_type_name(conn->type),
 | 
				
			||||||
				"rtp:%u rtcp:%u)",
 | 
									   conn->id,
 | 
				
			||||||
				conn->name, conn->id,
 | 
									   osmo_sockaddr_ntop(&conn_rtp->end.addr.u.sa, ipbuf) ? : "NULL",
 | 
				
			||||||
				osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
									   osmo_sockaddr_port(&conn_rtp->end.addr.u.sa),
 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
									   conn_rtp->end.local_addr ? : "NULL",
 | 
				
			||||||
				ntohs(conn->u.rtp.end.rtcp_port));
 | 
									   conn_rtp->end.local_port);
 | 
				
			||||||
			break;
 | 
					
 | 
				
			||||||
 | 
							switch (conn_rtp->type) {
 | 
				
			||||||
		case MGCP_RTP_OSMUX:
 | 
							case MGCP_RTP_OSMUX:
 | 
				
			||||||
			snprintf(str, sizeof(str), "(%s/osmux, id:0x%s, ip:%s, "
 | 
								OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_rtp->osmux.local_cid);
 | 
				
			||||||
				"port:%u CID:%u)",
 | 
					 | 
				
			||||||
				conn->name, conn->id,
 | 
					 | 
				
			||||||
				osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
					 | 
				
			||||||
				conn->u.rtp.osmux.local_cid);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case MGCP_RTP_IUUP:
 | 
					 | 
				
			||||||
			snprintf(str, sizeof(str), "(%s/iuup, id:0x%s, ip:%s, "
 | 
					 | 
				
			||||||
				"port:%u)",
 | 
					 | 
				
			||||||
				conn->name, conn->id,
 | 
					 | 
				
			||||||
				osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* Should not happen, we should be able to dump
 | 
					 | 
				
			||||||
			 * every possible connection type. */
 | 
					 | 
				
			||||||
			snprintf(str, sizeof(str), "(unknown conn_rtp connection type %u)",
 | 
					 | 
				
			||||||
				 conn->u.rtp.type);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OSMO_STRBUF_PRINTF(sb, ")");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* Should not happen, we should be able to dump
 | 
							/* Should not happen, we should be able to dump
 | 
				
			||||||
		 * every possible connection type. */
 | 
							 * every possible connection type. */
 | 
				
			||||||
		snprintf(str, sizeof(str), "(unknown connection type)");
 | 
							return "(unknown connection type)";
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return str;
 | 
						return str;
 | 
				
			||||||
@@ -432,12 +346,9 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! get oldest connection in the list.
 | 
					const struct value_string mgcp_conn_rtp_type_names[] = {
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
						{ MGCP_RTP_DEFAULT, "rtp" },
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
 | 
						{ MGCP_RTP_OSMUX, "osmux" },
 | 
				
			||||||
{
 | 
						{ MGCP_RTP_IUUP, "iuup" },
 | 
				
			||||||
	if (llist_empty(&endp->conns))
 | 
						{}
 | 
				
			||||||
		return NULL;
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,133 +56,147 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
 | 
				
			|||||||
	.sign_link = NULL,
 | 
						.sign_link = NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* EFR idle frame */
 | 
					/* The following EFR TRAU-DL frame is a dummy to be transmitted in the absence
 | 
				
			||||||
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * of RTP-derived TRAU-DL frames.  The payload bit content here is the decoder
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * homing frame (DHF) of TS 46.060 section 8.2 Table 7 - the best we can do
 | 
				
			||||||
				      1, 1, 1, 0, 1, 0, 0, 0,
 | 
					 * in the absence of a proper TFO transform for EFR - while the full TRAU-DL
 | 
				
			||||||
				      0, 0, 0, 0, 1, 0, 0, 0,
 | 
					 * frame was generated by passing said EFR DHF through osmo_rtp2trau().
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
					 */
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_efr[] = {
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 0, 1, 1, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 0, 1, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 0, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 1, 1, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 0, 1, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 1, 0,
 | 
						1, 1, 1, 0, 1, 0, 1, 1,
 | 
				
			||||||
				      1, 1, 1, 1, 1, 1, 1, 1,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FR idle frame */
 | 
					/* The following FRv1 TRAU-DL frame is a dummy to be transmitted in the absence
 | 
				
			||||||
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * of RTP-derived TRAU-DL frames.  The payload bit content here is the silence
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * frame of TS 46.011 Table 1 - the best we can do without integrating the
 | 
				
			||||||
				     1, 1, 1, 1, 0, 0, 0, 0,
 | 
					 * TFO transform for FRv1 from Themyscira libgsmfr2 - while the full TRAU-DL
 | 
				
			||||||
				     0, 0, 0, 0, 1, 0, 0, 0,
 | 
					 * frame was generated by passing said FRv1 silence frame through
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * osmo_rtp2trau().
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 */
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_fr[] = {
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 1, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 0, 1, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 0, 1, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 0, 0, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 1, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 1, 1, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 0, 0, 1, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 1, 0, 0, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 1, 0,
 | 
						1, 0, 0, 0, 0, 1, 0, 1,
 | 
				
			||||||
				     1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 1, 1, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
 | 
						0, 0, 0, 1, 0, 0, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
 | 
					/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
 | 
				
			||||||
static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_spch[] = {
 | 
				
			||||||
				       0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				       1, 0, 1, 1, 1, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				       0, 0, 0, 0, 1, 0, 0, 0,
 | 
						1, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						0, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 0,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 0,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
 | 
					/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
 | 
				
			||||||
@@ -301,7 +315,6 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
 | 
						mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
skip:
 | 
					skip:
 | 
				
			||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
 | 
				
			||||||
@@ -325,7 +338,7 @@ static void e1_send_ts_frame(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
				
			|||||||
				     msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
									     msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	/* Hand data over to the E1 stack */
 | 
						/* Hand data over to the E1 stack */
 | 
				
			||||||
	msgb_enqueue(&ts->raw.tx_queue, msg);
 | 
						e1inp_ts_send_raw(ts, msg);
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -466,11 +479,21 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
		return OSMO_TRAU16_FT_FR;
 | 
							return OSMO_TRAU16_FT_FR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
		return OSMO_TRAU16_FT_EFR;
 | 
							return OSMO_TRAU16_FT_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
					
 | 
				
			||||||
		return OSMO_TRAU16_FT_HR;
 | 
						if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
							if (i460_rate == OSMO_I460_RATE_16k)
 | 
				
			||||||
 | 
								return OSMO_TRAU16_FT_HR;
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k)
 | 
				
			||||||
 | 
								return OSMO_TRAU8_SPEECH;
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
 | 
				
			||||||
 | 
							return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
		if (i460_rate == OSMO_I460_RATE_8k) {
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
			switch (amr_ft) {
 | 
								switch (amr_ft) {
 | 
				
			||||||
			case AMR_4_75:
 | 
								case AMR_4_75:
 | 
				
			||||||
@@ -488,11 +511,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return OSMO_TRAU16_FT_AMR;
 | 
							return OSMO_TRAU16_FT_AMR;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
					 | 
				
			||||||
			 sdp_subtype_name);
 | 
					 | 
				
			||||||
		return OSMO_TRAU_FT_NONE;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
							 sdp_subtype_name);
 | 
				
			||||||
 | 
						return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Determine a suitable TRAU frame type for a given codec */
 | 
					/* Determine a suitable TRAU frame type for a given codec */
 | 
				
			||||||
@@ -501,11 +524,21 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
					
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_8_HR;
 | 
						if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
							if (i460_rate == OSMO_I460_RATE_16k)
 | 
				
			||||||
 | 
								return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k)
 | 
				
			||||||
 | 
								return OSMO_TRAU_SYNCP_8_HR;
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
		if (i460_rate == OSMO_I460_RATE_8k) {
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
			switch (amr_ft) {
 | 
								switch (amr_ft) {
 | 
				
			||||||
			case AMR_4_75:
 | 
								case AMR_4_75:
 | 
				
			||||||
@@ -523,11 +556,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
					 | 
				
			||||||
			 sdp_subtype_name);
 | 
					 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
							 sdp_subtype_name);
 | 
				
			||||||
 | 
						return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Find out if a given TRAU frame type is AMR */
 | 
					/* Find out if a given TRAU frame type is AMR */
 | 
				
			||||||
@@ -631,15 +664,17 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
				
			|||||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	enum osmo_tray_sync_pat_id sync_pat_id;
 | 
						enum osmo_tray_sync_pat_id sync_pat_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In order to determine the codec, find the oldest connection on
 | 
						/* In order to determine the codec, find the oldest connection on
 | 
				
			||||||
	 * the endpoint and use its codec information. Normally on an E1
 | 
						 * the endpoint and use its codec information. Normally on an E1
 | 
				
			||||||
	 * endpoint no more than one connection should exist. */
 | 
						 * endpoint no more than one connection should exist. */
 | 
				
			||||||
	conn = mgcp_conn_get_oldest(endp);
 | 
						conn = mgcp_endp_get_conn_oldest(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	codec = conn->u.rtp.end.codec;
 | 
						conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
						codec = conn_rtp->end.cset.codec;
 | 
				
			||||||
	OSMO_ASSERT(codec);
 | 
						OSMO_ASSERT(codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Update codec information */
 | 
						/* Update codec information */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Generate E1 endpoint name from given numeric parameters */
 | 
					/* Generate E1 endpoint name from given numeric parameters */
 | 
				
			||||||
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
 | 
					static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr,
 | 
				
			||||||
			   uint8_t ts_nr, uint8_t ss_nr)
 | 
								   uint8_t ts_nr, uint8_t ss_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int rate;
 | 
						unsigned int rate;
 | 
				
			||||||
@@ -446,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname)
 | 
				
			|||||||
/* Check if the selected E1 endpoint is avalable, which means that none of
 | 
					/* Check if the selected E1 endpoint is avalable, which means that none of
 | 
				
			||||||
 * the overlapping endpoints are currently serving a call. (if the system
 | 
					 * the overlapping endpoints are currently serving a call. (if the system
 | 
				
			||||||
 * is properly configured such a situation should never ocurr!) */
 | 
					 * is properly configured such a situation should never ocurr!) */
 | 
				
			||||||
static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
					static bool endp_avail_e1(const struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* The following map shows the overlapping of the subslots and their
 | 
						/* The following map shows the overlapping of the subslots and their
 | 
				
			||||||
	 * respective rates. The numbers on the right running from top to bottom
 | 
						 * respective rates. The numbers on the right running from top to bottom
 | 
				
			||||||
@@ -552,7 +552,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
				
			|||||||
/*! check if an endpoint is available for any kind of operation.
 | 
					/*! check if an endpoint is available for any kind of operation.
 | 
				
			||||||
 *  \param[in] endp endpoint to check.
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 *  \returns true if endpoint is avalable, false it is blocked for any reason. */
 | 
					 *  \returns true if endpoint is avalable, false it is blocked for any reason. */
 | 
				
			||||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
					bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (endp->trunk->trunk_type) {
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
	case MGCP_TRUNK_VIRTUAL:
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
@@ -569,6 +569,24 @@ bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get number of conns in an endpoint.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 | 
					 *  \returns Number of connections present in the endpoint. */
 | 
				
			||||||
 | 
					unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return llist_count(&endp->conns);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! check if an endpoint can in current state allocate new conns.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 | 
					 *  \returns true if more connections can be allowed on endpoint, false if it is already busy. */
 | 
				
			||||||
 | 
					bool mgcp_endp_is_full(const struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (endp->type->max_conns == 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return mgcp_endp_num_conns(endp) >= endp->type->max_conns;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
					/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
				
			||||||
 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
					 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
				
			||||||
 *  created.
 | 
					 *  created.
 | 
				
			||||||
@@ -655,6 +673,97 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
				
			|||||||
		mgcp_endp_release(endp);
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free oldest connection in the list.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
				
			||||||
 | 
						mgcp_conn_free(conn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free all connections at once.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					#if defined(__has_attribute)
 | 
				
			||||||
 | 
					#if __has_attribute(no_sanitize)
 | 
				
			||||||
 | 
					__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Drop all items in the list, might be consecutive! */
 | 
				
			||||||
 | 
						while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
				
			||||||
 | 
							mgcp_conn_free(conn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! find a connection by its ID.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint
 | 
				
			||||||
 | 
					 *  \param[in] id identification number of the connection
 | 
				
			||||||
 | 
					 *  \returns pointer to allocated connection, NULL if not found */
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
						const char *id_upper;
 | 
				
			||||||
 | 
						const char *conn_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!id || !*id)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Ignore leading zeros in needle */
 | 
				
			||||||
 | 
						while (*id == '0')
 | 
				
			||||||
 | 
							id++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
				
			||||||
 | 
						 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
				
			||||||
 | 
						 * we sent upper case hex in the CRCX response. */
 | 
				
			||||||
 | 
						id_upper = osmo_str_toupper(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
 | 
							/* Ignore leading zeros in haystack */
 | 
				
			||||||
 | 
							for (conn_id = conn->id; *conn_id == '0'; conn_id++);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(conn_id, id_upper) == 0)
 | 
				
			||||||
 | 
								return conn;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! get oldest connection in the list.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! find an RTP connection by its ID.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint
 | 
				
			||||||
 | 
					 *  \param[in] id identification number of the connection
 | 
				
			||||||
 | 
					 *  \returns pointer to allocated connection, NULL if not found */
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = mgcp_endp_get_conn(endp, id);
 | 
				
			||||||
 | 
						if (!conn)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
				
			||||||
 | 
							return mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! release endpoint, all open connections are closed.
 | 
					/*! release endpoint, all open connections are closed.
 | 
				
			||||||
 *  \param[in] endp endpoint to release */
 | 
					 *  \param[in] endp endpoint to release */
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
@@ -665,7 +774,7 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	 * all connections have been removed already. In case
 | 
						 * all connections have been removed already. In case
 | 
				
			||||||
	 * that there are still connections open (e.g. when
 | 
						 * that there are still connections open (e.g. when
 | 
				
			||||||
	 * RSIP is executed), free them all at once. */
 | 
						 * RSIP is executed), free them all at once. */
 | 
				
			||||||
	mgcp_conn_free_all(endp);
 | 
						mgcp_endp_free_conn_all(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We must only decrement the stat item when the endpoint as actually
 | 
						/* We must only decrement the stat item when the endpoint as actually
 | 
				
			||||||
	 * claimed. An endpoint is claimed when a call-id is set */
 | 
						 * claimed. An endpoint is claimed when a call-id is set */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -264,6 +264,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
	uint8_t *amr_data;
 | 
						uint8_t *amr_data;
 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	struct amr_hdr *amr_hdr;
 | 
						struct amr_hdr *amr_hdr;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *dst_codec;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
 | 
						ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
 | 
				
			||||||
@@ -275,7 +276,8 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	msgb_pull_to_l3(msg);
 | 
						msgb_pull_to_l3(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
						dst_codec = conn_rtp_dst->end.cset.codec;
 | 
				
			||||||
 | 
						if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
				
			||||||
		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
							amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
				
			||||||
		amr_hdr->cmr = 15; /* no change */
 | 
							amr_hdr->cmr = 15; /* no change */
 | 
				
			||||||
@@ -303,7 +305,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
		.extension = 0,
 | 
							.extension = 0,
 | 
				
			||||||
		.padding = 0,
 | 
							.padding = 0,
 | 
				
			||||||
		.version = 0,
 | 
							.version = 0,
 | 
				
			||||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
							.payload_type = dst_codec->payload_type,
 | 
				
			||||||
		.marker = 0,
 | 
							.marker = 0,
 | 
				
			||||||
		.sequence = frame_nr,
 | 
							.sequence = frame_nr,
 | 
				
			||||||
		.timestamp = 0,
 | 
							.timestamp = 0,
 | 
				
			||||||
@@ -311,7 +313,6 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
 | 
						rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -469,7 +470,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
	int buflen = msgb_length(msg);
 | 
						int buflen = msgb_length(msg);
 | 
				
			||||||
	char *dest_name;
 | 
						char *dest_name;
 | 
				
			||||||
	int len;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(conn_src);
 | 
						OSMO_ASSERT(conn_src);
 | 
				
			||||||
	OSMO_ASSERT(conn_dst);
 | 
						OSMO_ASSERT(conn_dst);
 | 
				
			||||||
@@ -503,9 +504,10 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	 * ignored by the receiver, but still it's useful for debug purposes
 | 
						 * ignored by the receiver, but still it's useful for debug purposes
 | 
				
			||||||
	 * to set it. Moreover, it seems ip.access nano3g produces much worse
 | 
						 * to set it. Moreover, it seems ip.access nano3g produces much worse
 | 
				
			||||||
	 * audio output on the air side if timestamp is not set properly. */
 | 
						 * audio output on the air side if timestamp is not set properly. */
 | 
				
			||||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
						hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
 | 
				
			||||||
	hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
						hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
				
			||||||
	hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
						hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
						rtp_state->alt_rtp_tx_sequence++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
						LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
		 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
							 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
@@ -513,19 +515,17 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
		 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
 | 
							 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
	forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
						forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
 | 
				
			||||||
		     msg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
 | 
						rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len <= 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return len;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
 | 
				
			||||||
	rtp_state->alt_rtp_tx_sequence++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return len;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
 | 
					/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
 | 
				
			||||||
@@ -546,13 +546,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	msgb_pull_to_l2(msg);
 | 
						msgb_pull_to_l2(msg);
 | 
				
			||||||
	rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
 | 
						rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
 | 
				
			||||||
	/* TODO: fill rtph properly: */
 | 
						/* rtph is further filled in mgcp_send_iuup() below. */
 | 
				
			||||||
	*rtph = (struct rtp_hdr){
 | 
						*rtph = (struct rtp_hdr){
 | 
				
			||||||
		.csrc_count = 0,
 | 
							.csrc_count = 0,
 | 
				
			||||||
		.extension = 0,
 | 
							.extension = 0,
 | 
				
			||||||
		.padding = 0,
 | 
							.padding = 0,
 | 
				
			||||||
		.version = 2,
 | 
							.version = 2,
 | 
				
			||||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
							.payload_type = conn_rtp_dst->end.cset.codec->payload_type,
 | 
				
			||||||
		.marker = 0,
 | 
							.marker = 0,
 | 
				
			||||||
		.sequence = 0,
 | 
							.sequence = 0,
 | 
				
			||||||
		.timestamp = 0,
 | 
							.timestamp = 0,
 | 
				
			||||||
@@ -640,13 +640,14 @@ free_ret:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
 | 
					/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
 | 
				
			||||||
 * peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
 | 
					 * peer and send it down the IuUP layer towards the destination as IuUP/RTP. Takes ownership of msg. */
 | 
				
			||||||
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
 | 
					int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp;
 | 
						struct osmo_iuup_rnl_prim *irp;
 | 
				
			||||||
	struct rtp_hdr *rtph;
 | 
						struct rtp_hdr *rtph;
 | 
				
			||||||
	int rc = -1;
 | 
						int rc = -1;
 | 
				
			||||||
	int iuup_length = 0;
 | 
						int iuup_length = 0;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *src_codec;
 | 
				
			||||||
	int8_t rfci;
 | 
						int8_t rfci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Tx RNL-DATA.req */
 | 
						/* Tx RNL-DATA.req */
 | 
				
			||||||
@@ -659,13 +660,14 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* TODO: CMR handling & multiple frames handling */
 | 
						/* TODO: CMR handling & multiple frames handling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
 | 
						src_codec = conn_src_rtp->end.cset.codec;
 | 
				
			||||||
 | 
						if (strcmp(src_codec->subtype_name, "AMR") != 0) {
 | 
				
			||||||
		LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
 | 
							LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
 | 
				
			||||||
			     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
 | 
								     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
 | 
				
			||||||
			     conn_src_rtp->end.codec->subtype_name);
 | 
								     src_codec->subtype_name);
 | 
				
			||||||
		goto free_ret;
 | 
							goto free_ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
 | 
						if (mgcp_codec_amr_is_octet_aligned(src_codec)) {
 | 
				
			||||||
		struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
 | 
							struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
 | 
				
			||||||
		if (msgb_length(msg) < (sizeof(*amr_hdr))) {
 | 
							if (msgb_length(msg) < (sizeof(*amr_hdr))) {
 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
@@ -33,6 +34,10 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (same fmt as LOGPENDP()) */
 | 
				
			||||||
 | 
					#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LEVEL, "endpoint:%s " FMT, (PDATA) ? ((PDATA)->epname ? : "null-epname") : "null-pdata", ##ARGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Display an mgcp message on the log output.
 | 
					/*! Display an mgcp message on the log output.
 | 
				
			||||||
 *  \param[in] message mgcp message string
 | 
					 *  \param[in] message mgcp message string
 | 
				
			||||||
 *  \param[in] len message mgcp message string length
 | 
					 *  \param[in] len message mgcp message string length
 | 
				
			||||||
@@ -76,61 +81,24 @@ 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 confecho or loopback)
 | 
				
			||||||
 *  \param[in] endp pointer to endpoint (only used for log output)
 | 
					 *  \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */
 | 
				
			||||||
 *  \param[out] associated connection to be modified accordingly
 | 
					enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
 | 
				
			||||||
 *  \returns 0 on success, -1 on error */
 | 
					 | 
				
			||||||
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
			 struct mgcp_conn *conn)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mode) {
 | 
						if (!mode)
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
							return MGCP_CONN_NONE;
 | 
				
			||||||
			 "missing connection mode\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	if (!endp)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(mode, "recvonly") == 0)
 | 
						if (strcasecmp(mode, "recvonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_ONLY;
 | 
							return MGCP_CONN_RECV_ONLY;
 | 
				
			||||||
	else if (strcasecmp(mode, "sendrecv") == 0)
 | 
						if (strcasecmp(mode, "sendrecv") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_SEND;
 | 
							return MGCP_CONN_RECV_SEND;
 | 
				
			||||||
	else if (strcasecmp(mode, "sendonly") == 0)
 | 
						if (strcasecmp(mode, "sendonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_SEND_ONLY;
 | 
							return MGCP_CONN_SEND_ONLY;
 | 
				
			||||||
	else if (strcasecmp(mode, "confecho") == 0)
 | 
						if (strcasecmp(mode, "confecho") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_CONFECHO;
 | 
							return MGCP_CONN_CONFECHO;
 | 
				
			||||||
	else if (strcasecmp(mode, "loopback") == 0)
 | 
						if (strcasecmp(mode, "loopback") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_LOOPBACK;
 | 
							return MGCP_CONN_LOOPBACK;
 | 
				
			||||||
	else {
 | 
						return MGCP_CONN_NONE;
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "unknown connection mode: '%s'\n", mode);
 | 
					 | 
				
			||||||
		ret = -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Special handling for RTP connections */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
					 | 
				
			||||||
		conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
					 | 
				
			||||||
		 mode, conn->mode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Special handling für RTP connections */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
					 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
					 | 
				
			||||||
			 conn->u.rtp.end.output_enabled);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The VTY might change the connection mode at any time, so we have
 | 
					 | 
				
			||||||
	 * to hold a copy of the original connection mode */
 | 
					 | 
				
			||||||
	conn->mode_orig = conn->mode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
					/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
				
			||||||
@@ -159,8 +127,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 2:
 | 
							case 2:
 | 
				
			||||||
			if (strcasecmp("MGCP", elem)) {
 | 
								if (strcasecmp("MGCP", elem)) {
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
									LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
 | 
				
			||||||
				     "MGCP header parsing error\n");
 | 
					 | 
				
			||||||
				return -510;
 | 
									return -510;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -173,13 +140,87 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (i != 4) {
 | 
						if (i != 4) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
 | 
							LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n");
 | 
				
			||||||
		return -510;
 | 
							return -510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *saveptr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						line += strlen(MGCP_X_OSMO_IGN_HEADER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							char *token = strtok_r(line, " ", &saveptr);
 | 
				
			||||||
 | 
							line = NULL;
 | 
				
			||||||
 | 
							if (!token)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!strcasecmp(token, "C"))
 | 
				
			||||||
 | 
								pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Analyze and parse the the header of an MGCP message string.
 | 
				
			||||||
 | 
					 *  \param[inout] pdata caller provided memory to store the parsing results.
 | 
				
			||||||
 | 
					 *  \returns 0 when parsing was successful, negative (MGCP cause code) on error. */
 | 
				
			||||||
 | 
					int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
 | 
				
			||||||
 | 
						char *line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_parse_hdr_pars_init(hp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_line(line, pdata->save) {
 | 
				
			||||||
 | 
							if (!mgcp_check_param(line)) {
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
 | 
							case 'L':
 | 
				
			||||||
 | 
								hp->local_options = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'C':
 | 
				
			||||||
 | 
								hp->callid = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'I':
 | 
				
			||||||
 | 
								hp->connid = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'M':
 | 
				
			||||||
 | 
								hp->mode = mgcp_parse_conn_mode((const char *)line + 3);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'X':
 | 
				
			||||||
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
 | 
									hp->remote_osmux_cid = mgcp_parse_osmux_cid(line);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (parse_x_osmo_ign(pdata, line))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '\0':
 | 
				
			||||||
 | 
								hp->have_sdp = true;
 | 
				
			||||||
 | 
								goto mgcp_header_done;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
				
			||||||
 | 
								return -539;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mgcp_header_done:
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
					/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
				
			||||||
 *  \param[in] line single parameter line from the MGCP message
 | 
					 *  \param[in] line single parameter line from the MGCP message
 | 
				
			||||||
 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
					 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
				
			||||||
@@ -190,19 +231,19 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
						if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
				
			||||||
		return -1;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
						if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
				
			||||||
		     line);
 | 
							     line);
 | 
				
			||||||
		return -2;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmux_cid > OSMUX_CID_MAX) {
 | 
						if (osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
				
			||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,20 +251,13 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Check MGCP parameter line (string) for plausibility.
 | 
					/*! Check MGCP parameter line (string) for plausibility.
 | 
				
			||||||
 *  \param[in] endp pointer to endpoint (only used for log output, may be NULL)
 | 
					 | 
				
			||||||
 *  \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
 | 
					 | 
				
			||||||
 *  \param[in] line single parameter line from the MGCP message
 | 
					 *  \param[in] line single parameter line from the MGCP message
 | 
				
			||||||
 *  \returns true when line seems plausible, false on error */
 | 
					 *  \returns true when line seems plausible, false on error */
 | 
				
			||||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
 | 
					bool mgcp_check_param(const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const size_t line_len = strlen(line);
 | 
						const size_t line_len = strlen(line);
 | 
				
			||||||
	if (line[0] != '\0' && line_len < 2) {
 | 
						if (line[0] != '\0' && line_len < 2)
 | 
				
			||||||
		if (endp)
 | 
					 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: A couple more checks wouldn't hurt... */
 | 
						/* FIXME: A couple more checks wouldn't hurt... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -294,7 +328,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if connection exists */
 | 
						/* Check if connection exists */
 | 
				
			||||||
	if (mgcp_conn_get(endp, conn_id))
 | 
						if (mgcp_endp_get_conn(endp, conn_id))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
					 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 * (C) 2009-2012 by On-Waves
 | 
					 * (C) 2009-2012 by On-Waves
 | 
				
			||||||
 | 
					 * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
@@ -70,14 +71,20 @@ void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
 | 
				
			|||||||
	rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
						rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rx_rtp(struct msgb *msg);
 | 
					/* wrapper around libosmocore msgb_copy_c, which [at least before libosmocore.git Change-Id
 | 
				
			||||||
 | 
					 * I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5] doesn't copy the cb */
 | 
				
			||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
					static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
						struct msgb *msg2 = msgb_copy_c(ctx, msg, name);
 | 
				
			||||||
	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
						if (OSMO_UNLIKELY(!msg2))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(msg2->cb, msg->cb, sizeof(msg2->cb));
 | 
				
			||||||
 | 
						return msg2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_rtp(struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Determine the local rtp bind IP-address.
 | 
					/*! Determine the local rtp bind IP-address.
 | 
				
			||||||
 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
					 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
				
			||||||
 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
					 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
				
			||||||
@@ -325,7 +332,7 @@ static int adjust_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
									 osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
				
			||||||
				 osmo_sockaddr_port(&addr->u.sa));
 | 
									 osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			tsdelta = rtp_end->codec->rate * 20 / 1000;
 | 
								tsdelta = rtp_end->cset.codec->rate * 20 / 1000;
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
				
			||||||
				 "Fixed packet duration and last timestamp delta "
 | 
									 "Fixed packet duration and last timestamp delta "
 | 
				
			||||||
				 "are not available, "
 | 
									 "are not available, "
 | 
				
			||||||
@@ -404,15 +411,12 @@ static int align_rtp_timestamp_offset(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
 | 
					/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
 | 
				
			||||||
 *  \param[in] associated endpoint.
 | 
					 *  \param[in] associated endpoint.
 | 
				
			||||||
 *  \param[in] destination RTP end.
 | 
					 *  \param[in] destination RTP end.
 | 
				
			||||||
 *  \param[in,out] pointer to buffer with voice data.
 | 
					 *  \param[in,out] msg message bufffer containing data. Function might change length.
 | 
				
			||||||
 *  \param[in] voice data length.
 | 
					 | 
				
			||||||
 *  \param[in] maximum size of caller provided voice data buffer.
 | 
					 | 
				
			||||||
 *  \returns ignores input parameters, return always 0. */
 | 
					 *  \returns ignores input parameters, return always 0. */
 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
				struct mgcp_rtp_end *dst_end,
 | 
									struct mgcp_rtp_end *dst_end,
 | 
				
			||||||
				char *data, int *len, int buf_size)
 | 
									struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG, "transcoding disabled\n");
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -429,18 +433,6 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
					  const struct mgcp_rtp_codec **codec,
 | 
					 | 
				
			||||||
					  const char **fmtp_extra,
 | 
					 | 
				
			||||||
					  struct mgcp_conn_rtp *conn)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG, "conn:%s using format defaults\n",
 | 
					 | 
				
			||||||
		 mgcp_conn_dump(conn->conn));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*codec = conn->end.codec;
 | 
					 | 
				
			||||||
	*fmtp_extra = conn->end.fmtp_extra;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp,
 | 
					void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp,
 | 
				
			||||||
			  struct mgcp_rtp_state *state, const uint16_t seq,
 | 
								  struct mgcp_rtp_state *state, const uint16_t seq,
 | 
				
			||||||
			  const int32_t transit, const uint32_t ssrc,
 | 
								  const int32_t transit, const uint32_t ssrc,
 | 
				
			||||||
@@ -504,11 +496,11 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn_dst->end.codec) {
 | 
						if (!conn_dst->end.cset.codec) {
 | 
				
			||||||
		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
 | 
							LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type;
 | 
						rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -531,7 +523,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	uint32_t timestamp, ssrc;
 | 
						uint32_t timestamp, ssrc;
 | 
				
			||||||
	bool marker_bit;
 | 
						bool marker_bit;
 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	int payload = rtp_end->codec->payload_type;
 | 
						struct mgcp_rtp_codec *codec = rtp_end->cset.codec;
 | 
				
			||||||
 | 
						int payload = codec->payload_type;
 | 
				
			||||||
	unsigned int len = msgb_length(msg);
 | 
						unsigned int len = msgb_length(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len < sizeof(*rtp_hdr))
 | 
						if (len < sizeof(*rtp_hdr))
 | 
				
			||||||
@@ -540,7 +533,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
	seq = ntohs(rtp_hdr->sequence);
 | 
						seq = ntohs(rtp_hdr->sequence);
 | 
				
			||||||
	timestamp = ntohl(rtp_hdr->timestamp);
 | 
						timestamp = ntohl(rtp_hdr->timestamp);
 | 
				
			||||||
	arrival_time = mgcp_get_current_ts(rtp_end->codec->rate);
 | 
						arrival_time = mgcp_get_current_ts(codec->rate);
 | 
				
			||||||
	ssrc = ntohl(rtp_hdr->ssrc);
 | 
						ssrc = ntohl(rtp_hdr->ssrc);
 | 
				
			||||||
	marker_bit = !!rtp_hdr->marker;
 | 
						marker_bit = !!rtp_hdr->marker;
 | 
				
			||||||
	transit = arrival_time - timestamp;
 | 
						transit = arrival_time - timestamp;
 | 
				
			||||||
@@ -549,16 +542,16 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (!state->initialized) {
 | 
						if (!state->initialized) {
 | 
				
			||||||
		state->initialized = 1;
 | 
							state->initialized = 1;
 | 
				
			||||||
 | 
							state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end);
 | 
				
			||||||
		state->in_stream.last_seq = seq - 1;
 | 
							state->in_stream.last_seq = seq - 1;
 | 
				
			||||||
		state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
 | 
							state->in_stream.ssrc = ssrc;
 | 
				
			||||||
		state->in_stream.last_tsdelta = 0;
 | 
							state->in_stream.last_tsdelta = 0;
 | 
				
			||||||
		state->packet_duration =
 | 
					 | 
				
			||||||
		    mgcp_rtp_packet_duration(endp, rtp_end);
 | 
					 | 
				
			||||||
		state->out_stream.last_seq = seq - 1;
 | 
							state->out_stream.last_seq = seq - 1;
 | 
				
			||||||
		state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
 | 
					 | 
				
			||||||
		state->out_stream.last_tsdelta = 0;
 | 
							state->out_stream.last_tsdelta = 0;
 | 
				
			||||||
		state->out_stream.last_timestamp = timestamp;
 | 
							state->out_stream.last_timestamp = timestamp;
 | 
				
			||||||
		state->out_stream.ssrc = ssrc - 1;	/* force output SSRC change */
 | 
							state->out_stream.ssrc = ssrc - 1;	/* force output SSRC change */
 | 
				
			||||||
 | 
							state->patch.orig_ssrc = ssrc;
 | 
				
			||||||
 | 
							state->patch.patch_ssrc = rtp_end->force_constant_ssrc;
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_INFO,
 | 
							LOGPENDP(endp, DRTP, LOGL_INFO,
 | 
				
			||||||
			 "initializing stream, SSRC: %u timestamp: %u "
 | 
								 "initializing stream, SSRC: %u timestamp: %u "
 | 
				
			||||||
			 "pkt-duration: %d, from %s:%d\n",
 | 
								 "pkt-duration: %d, from %s:%d\n",
 | 
				
			||||||
@@ -568,7 +561,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
								 osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
		if (state->packet_duration == 0) {
 | 
							if (state->packet_duration == 0) {
 | 
				
			||||||
			state->packet_duration =
 | 
								state->packet_duration =
 | 
				
			||||||
			    rtp_end->codec->rate * 20 / 1000;
 | 
								    codec->rate * 20 / 1000;
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
				
			||||||
				 "fixed packet duration is not available, "
 | 
									 "fixed packet duration is not available, "
 | 
				
			||||||
				 "using fixed 20ms instead: %d from %s:%d\n",
 | 
									 "using fixed 20ms instead: %d from %s:%d\n",
 | 
				
			||||||
@@ -585,7 +578,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
								 osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->in_stream.ssrc = ssrc;
 | 
							state->in_stream.ssrc = ssrc;
 | 
				
			||||||
		if (rtp_end->force_constant_ssrc) {
 | 
							if (state->patch.patch_ssrc) {
 | 
				
			||||||
			int16_t delta_seq;
 | 
								int16_t delta_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Always increment seqno by 1 */
 | 
								/* Always increment seqno by 1 */
 | 
				
			||||||
@@ -601,10 +594,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
 | 
								adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
 | 
				
			||||||
						    delta_seq, timestamp, marker_bit);
 | 
											    delta_seq, timestamp, marker_bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			state->patch.patch_ssrc = true;
 | 
					 | 
				
			||||||
			ssrc = state->patch.orig_ssrc;
 | 
								ssrc = state->patch.orig_ssrc;
 | 
				
			||||||
			if (rtp_end->force_constant_ssrc != -1)
 | 
					 | 
				
			||||||
				rtp_end->force_constant_ssrc -= 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DRTP, LOGL_NOTICE,
 | 
				
			||||||
				 "SSRC patching enabled, SSRC: %u "
 | 
									 "SSRC patching enabled, SSRC: %u "
 | 
				
			||||||
@@ -797,16 +787,18 @@ static int amr_oa_check(char *data, int len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Forward data to a debug tap. This is debug function that is intended for
 | 
					/* Forward data to a debug tap. This is debug function that is intended for
 | 
				
			||||||
 * debugging the voice traffic with tools like gstreamer */
 | 
					 * debugging the voice traffic with tools like gstreamer */
 | 
				
			||||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
 | 
					void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!tap->enabled)
 | 
						if (!tap->enabled)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = sendto(fd, msgb_data(msg), msgb_length(msg), 0, (struct sockaddr *)&tap->forward,
 | 
						struct msgb *msg2 = msgb_copy(msg, "RTP TAP Tx");
 | 
				
			||||||
		    sizeof(tap->forward));
 | 
						if (!msg2)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_iofd_sendto_msgb(iofd, msg2, 0, &tap->forward);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		LOGP(DRTP, LOGL_ERROR,
 | 
							LOGP(DRTP, LOGL_ERROR,
 | 
				
			||||||
		     "Forwarding tapped (debug) voice data failed.\n");
 | 
							     "Forwarding tapped (debug) voice data failed.\n");
 | 
				
			||||||
@@ -822,8 +814,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdr->version = 2;
 | 
						hdr->version = 2;
 | 
				
			||||||
	hdr->payload_type = rtp_end->codec->payload_type;
 | 
						hdr->payload_type = rtp_end->cset.codec->payload_type;
 | 
				
			||||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
						hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate));
 | 
				
			||||||
	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
 | 
						hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
 | 
				
			||||||
	hdr->ssrc = state->alt_rtp_tx_ssrc;
 | 
						hdr->ssrc = state->alt_rtp_tx_ssrc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -834,32 +826,27 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmo_sockaddr_is_any(&conn->end.addr) != 0) {
 | 
						if (osmo_sockaddr_is_any(&conn->end.addr) != 0 ||
 | 
				
			||||||
		switch (conn->conn->mode) {
 | 
						    osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
 | 
				
			||||||
		case MGCP_CONN_LOOPBACK:
 | 
							if (mgcp_conn_rtp_is_iuup(conn) && !conn->iuup.configured) {
 | 
				
			||||||
			/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
 | 
								/* Allow IuUP Initialization to get through even if we don't have a remote address set yet.
 | 
				
			||||||
			 * message received. We currently hackishly accomplish that by putting the endpoint in
 | 
								 * This is needed because hNodeB doesn't announce its IuUP remote IP addr to the MGCP client
 | 
				
			||||||
			 * loopback mode and patching over the looped back RTP message to make it look like an
 | 
								 * (RAB Assignment Response at HNBGW) until it has gone through IuUP Initialization against
 | 
				
			||||||
			 * ack. We don't know the femto cell's IP address and port until the RAB Assignment
 | 
								 * this MGW here. Hence the MGW may not yet know the remote IuUP address and port at the time
 | 
				
			||||||
			 * Response is received, but the nano3G expects an IuUP Initialization Ack before it even
 | 
								 * of receiving IuUP Initialization from the hNodeB.
 | 
				
			||||||
			 * sends the RAB Assignment Response. Hence, if the remote address is 0.0.0.0 and the
 | 
								 */
 | 
				
			||||||
			 * MGCP port is in loopback mode, allow looping back the packet to any source. */
 | 
					 | 
				
			||||||
			LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
				 "In loopback mode and remote address not set:"
 | 
					 | 
				
			||||||
				 " allowing data from address: %s\n",
 | 
					 | 
				
			||||||
				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			/* Receiving early media before the endpoint is configured. Instead of logging
 | 
					 | 
				
			||||||
			 * this as an error that occurs on every call, keep it more low profile to not
 | 
					 | 
				
			||||||
			 * confuse humans with expected errors. */
 | 
					 | 
				
			||||||
			LOGPCONN(conn->conn, DRTP, LOGL_INFO,
 | 
								LOGPCONN(conn->conn, DRTP, LOGL_INFO,
 | 
				
			||||||
				 "Rx RTP from %s, but remote address not set:"
 | 
									 "Rx RTP from %s: allowing unknown src for IuUP Initialization\n",
 | 
				
			||||||
				 " dropping early media\n",
 | 
									 osmo_sockaddr_to_str(addr));
 | 
				
			||||||
				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
 | 
								return 0;
 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							/* Receiving early media before the endpoint is configured. Instead of logging
 | 
				
			||||||
 | 
							 * this as an error that occurs on every call, keep it more low profile to not
 | 
				
			||||||
 | 
							 * confuse humans with expected errors. */
 | 
				
			||||||
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_INFO,
 | 
				
			||||||
 | 
								 "Rx RTP from %s, but remote address not set: dropping early media\n",
 | 
				
			||||||
 | 
								 osmo_sockaddr_to_str(addr));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: Check if the inbound RTP data comes from the same host to
 | 
						/* Note: Check if the inbound RTP data comes from the same host to
 | 
				
			||||||
@@ -871,11 +858,8 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
	     memcmp(&conn->end.addr.u.sin6.sin6_addr, &addr->u.sin6.sin6_addr,
 | 
						     memcmp(&conn->end.addr.u.sin6.sin6_addr, &addr->u.sin6.sin6_addr,
 | 
				
			||||||
		    sizeof(struct in6_addr)))) {
 | 
							    sizeof(struct in6_addr)))) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "data from wrong address: %s, ",
 | 
								 "data from wrong src %s, expected IP Address %s. Packet tossed.\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&addr->u.sa, ipbuf));
 | 
								 osmo_sockaddr_to_str(addr), osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
				
			||||||
		LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
 | 
					 | 
				
			||||||
		      osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
					 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -886,12 +870,9 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
	if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
						if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
				
			||||||
	    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
						    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "data from wrong source port: %d, ",
 | 
								 "data from wrong src %s, expected port: %u for RTP or %u for RTCP. Packet tossed.\n",
 | 
				
			||||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
								 osmo_sockaddr_to_str(addr), osmo_sockaddr_port(&conn->end.addr.u.sa),
 | 
				
			||||||
		LOGPC(DRTP, LOGL_ERROR,
 | 
								 ntohs(conn->end.rtcp_port));
 | 
				
			||||||
		      "expected: %d for RTP or %d for RTCP\n",
 | 
					 | 
				
			||||||
		      osmo_sockaddr_port(&conn->end.addr.u.sa), ntohs(conn->end.rtcp_port));
 | 
					 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -989,7 +970,7 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dispatch msg bridged from the sister conn in the endpoint.
 | 
					/*! Dispatch msg bridged from the sister conn in the endpoint. Takes ownership of msgb.
 | 
				
			||||||
 *  \param[in] conn_dst The destination conn that should handle and transmit the content to
 | 
					 *  \param[in] conn_dst The destination conn that should handle and transmit the content to
 | 
				
			||||||
 *			its peer outside MGW.
 | 
					 *			its peer outside MGW.
 | 
				
			||||||
 *  \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
 | 
					 *  \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
 | 
				
			||||||
@@ -1011,8 +992,10 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
 | 
				
			|||||||
	/* Before we try to deliver the packet, we check if the destination
 | 
						/* Before we try to deliver the packet, we check if the destination
 | 
				
			||||||
	 * port and IP-Address make sense at all. If not, we will be unable
 | 
						 * port and IP-Address make sense at all. If not, we will be unable
 | 
				
			||||||
	 * to deliver the packet. */
 | 
						 * to deliver the packet. */
 | 
				
			||||||
	if (check_rtp_destin(conn_dst) != 0)
 | 
						if (check_rtp_destin(conn_dst) != 0) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Depending on the RTP connection type, deliver the RTP packet to the
 | 
						/* Depending on the RTP connection type, deliver the RTP packet to the
 | 
				
			||||||
	 * destination connection. */
 | 
						 * destination connection. */
 | 
				
			||||||
@@ -1047,39 +1030,46 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
 | 
				
			|||||||
	 * be discarded, this should not happen, normally the MGCP type
 | 
						 * be discarded, this should not happen, normally the MGCP type
 | 
				
			||||||
	 * should be properly set */
 | 
						 * should be properly set */
 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
 | 
						LOGPENDP(endp, DRTP, LOGL_ERROR, "bad MGCP type -- data discarded!\n");
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! send udp packet.
 | 
					/*! send message buffer via udp socket.  If it succeeds, it takes ownership of the msgb and internally calls
 | 
				
			||||||
 *  \param[in] fd associated file descriptor.
 | 
					 *  msgb_free() after the aynchronous sendto() completes.  In case of error, the msgb is still owned by the
 | 
				
			||||||
 | 
					 *  caller and must be free'd accordingly.
 | 
				
			||||||
 | 
					 *  \param[in] iofd associated file descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] addr destination ip-address.
 | 
				
			||||||
 | 
					 *  \param[in] msg message buffer that holds the data to be send.
 | 
				
			||||||
 | 
					 *  \returns 0 in case of success (takes msgb ownership), -1 on error (doesn't take msgb ownership). */
 | 
				
			||||||
 | 
					static int mgcp_udp_send_msg(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGP(DRTP, LOGL_DEBUG, "sending %d bytes length packet to %s ...\n", msgb_length(msg),
 | 
				
			||||||
 | 
						     osmo_sockaddr_to_str(addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return osmo_iofd_sendto_msgb(iofd, msg, 0, addr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! send udp packet from raw buffer/length.
 | 
				
			||||||
 | 
					 *  \param[in] iofd associated file descriptor.
 | 
				
			||||||
 *  \param[in] addr destination ip-address.
 | 
					 *  \param[in] addr destination ip-address.
 | 
				
			||||||
 *  \param[in] buf buffer that holds the data to be send.
 | 
					 *  \param[in] buf buffer that holds the data to be send.
 | 
				
			||||||
 *  \param[in] len length of the data to be sent.
 | 
					 *  \param[in] len length of the data to be sent.
 | 
				
			||||||
 *  \returns bytes sent, -1 on error. */
 | 
					 *  \returns 0 in case of success, -1 on error. */
 | 
				
			||||||
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
 | 
					int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						struct msgb *msg = msgb_alloc_c(iofd, len, "mgcp_udp_send");
 | 
				
			||||||
	size_t addr_len;
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						memcpy(msg->tail, buf, len);
 | 
				
			||||||
 | 
						msgb_put(msg, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRTP, LOGL_DEBUG,
 | 
						return mgcp_udp_send_msg(iofd, addr, msg);
 | 
				
			||||||
	     "sending %i bytes length packet to %s:%u ...\n", len,
 | 
					 | 
				
			||||||
	     osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
					 | 
				
			||||||
	     osmo_sockaddr_port(&addr->u.sa));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (addr->u.sa.sa_family == AF_INET6) {
 | 
					 | 
				
			||||||
		addr_len = sizeof(addr->u.sin6);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		addr_len = sizeof(addr->u.sin);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return sendto(fd, buf, len, 0, &addr->u.sa, addr_len);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! send RTP dummy packet (to keep NAT connection open).
 | 
					/*! send RTP dummy packet (to keep NAT connection open).
 | 
				
			||||||
 *  \param[in] endp mcgp endpoint that holds the RTP connection.
 | 
					 *  \param[in] endp mcgp endpoint that holds the RTP connection.
 | 
				
			||||||
 *  \param[in] conn associated RTP connection.
 | 
					 *  \param[in] conn associated RTP connection.
 | 
				
			||||||
 *  \returns bytes sent, -1 on error. */
 | 
					 *  \returns 0 in case of success, -1 on error. */
 | 
				
			||||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -1101,8 +1091,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	if (mgcp_conn_rtp_is_iuup(conn))
 | 
						if (mgcp_conn_rtp_is_iuup(conn))
 | 
				
			||||||
		rc = mgcp_conn_iuup_send_dummy(conn);
 | 
							rc = mgcp_conn_iuup_send_dummy(conn);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
 | 
							rc = mgcp_udp_send(conn->end.rtp, &conn->end.addr, rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
				   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc == -1)
 | 
						if (rc == -1)
 | 
				
			||||||
		goto failed;
 | 
							goto failed;
 | 
				
			||||||
@@ -1113,10 +1102,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	was_rtcp = 1;
 | 
						was_rtcp = 1;
 | 
				
			||||||
	rtcp_addr = conn->end.addr;
 | 
						rtcp_addr = conn->end.addr;
 | 
				
			||||||
	osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
 | 
						osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
 | 
				
			||||||
	rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
 | 
						rc = mgcp_udp_send(conn->end.rtcp, &rtcp_addr,
 | 
				
			||||||
			   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
								   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc >= 0)
 | 
						if (rc == 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
failed:
 | 
					failed:
 | 
				
			||||||
@@ -1127,7 +1116,7 @@ failed:
 | 
				
			|||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Send RTP/RTCP data to a specified destination connection.
 | 
					/*! Send RTP/RTCP data to a specified destination connection. Takes ownership of msg.
 | 
				
			||||||
 *  \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] addr spoofed source address (set to NULL to disable).
 | 
				
			||||||
@@ -1166,6 +1155,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	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) {
 | 
							if (mgcp_patch_pt(conn_dst, msg) < 0) {
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_NOTICE, "unable to patch payload type RTP packet, discarding...\n");
 | 
								LOGPENDP(endp, DRTP, LOGL_NOTICE, "unable to patch payload type RTP packet, discarding...\n");
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1191,73 +1181,73 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
		    );
 | 
							    );
 | 
				
			||||||
	} else if (is_rtp) {
 | 
						} else if (is_rtp) {
 | 
				
			||||||
		int cont;
 | 
							struct mgcp_rtp_codec *src_codec;
 | 
				
			||||||
		int nbytes = 0;
 | 
							struct mgcp_rtp_codec *dst_codec;
 | 
				
			||||||
		int buflen = msgb_length(msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Make sure we have a valid RTP header, in cases where no RTP
 | 
							/* Make sure we have a valid RTP header, in cases where no RTP
 | 
				
			||||||
		 * header is present, we will generate one. */
 | 
							 * header is present, we will generate one. */
 | 
				
			||||||
		gen_rtp_header(msg, rtp_end, rtp_state);
 | 
							gen_rtp_header(msg, rtp_end, rtp_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		do {
 | 
							/* Run transcoder */
 | 
				
			||||||
			/* Run transcoder */
 | 
							rc = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, msg);
 | 
				
			||||||
			cont = endp->trunk->cfg->rtp_processing_cb(endp, rtp_end, (char *)msgb_data(msg), &buflen, RTP_BUF_SIZE);
 | 
							if (rc < 0) {
 | 
				
			||||||
			if (cont < 0)
 | 
								LOGPENDP(endp, DRTP, LOGL_ERROR, "Error %d during transcoding\n", rc);
 | 
				
			||||||
				break;
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (addr)
 | 
							if (addr)
 | 
				
			||||||
				mgcp_patch_and_count(endp, rtp_state, rtp_end,
 | 
								mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg);
 | 
				
			||||||
						     addr, msg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
							src_codec = conn_src->end.cset.codec;
 | 
				
			||||||
				/* the iuup code will correctly transform to the correct AMR mode */
 | 
							dst_codec = conn_dst->end.cset.codec;
 | 
				
			||||||
			} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
 | 
							if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
				
			||||||
				rc = amr_oa_bwe_convert(endp, msg,
 | 
								/* the iuup code will correctly transform to the correct AMR mode */
 | 
				
			||||||
							conn_dst->end.codec->param.amr_octet_aligned);
 | 
							} else if (mgcp_codec_amr_align_mode_is_indicated(dst_codec)) {
 | 
				
			||||||
				if (rc < 0) {
 | 
								rc = amr_oa_bwe_convert(endp, msg, dst_codec->param.amr_octet_aligned);
 | 
				
			||||||
					LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
								if (rc < 0) {
 | 
				
			||||||
						 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
 | 
									LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
				
			||||||
						 conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
										 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
 | 
				
			||||||
					break;
 | 
										 dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
				
			||||||
				}
 | 
									msgb_free(msg);
 | 
				
			||||||
			} else if (rtp_end->rfc5993_hr_convert &&
 | 
									return rc;
 | 
				
			||||||
				   strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) {
 | 
					 | 
				
			||||||
				rc = rfc5993_hr_convert(endp, msg);
 | 
					 | 
				
			||||||
				if (rc < 0) {
 | 
					 | 
				
			||||||
					LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
 | 
					 | 
				
			||||||
					break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							} else if (rtp_end->rfc5993_hr_convert &&
 | 
				
			||||||
 | 
								   strcmp(src_codec->subtype_name, "GSM-HR-08") == 0) {
 | 
				
			||||||
 | 
								rc = rfc5993_hr_convert(endp, msg);
 | 
				
			||||||
 | 
								if (rc < 0) {
 | 
				
			||||||
 | 
									LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n");
 | 
				
			||||||
 | 
									msgb_free(msg);
 | 
				
			||||||
 | 
									return rc;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
				 "process/send to %s %s "
 | 
								 "process/send to %s %s "
 | 
				
			||||||
				 "rtp_port:%u rtcp_port:%u\n",
 | 
								 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
				 dest_name,
 | 
								 dest_name,
 | 
				
			||||||
				 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
								 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
				 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
				);
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Forward a copy of the RTP data to a debug ip/port */
 | 
							/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
			forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
							forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
 | 
				
			||||||
				     msg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
 | 
							len = msgb_length(msg);
 | 
				
			||||||
					    (char *)msgb_data(msg), msgb_length(msg));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (len <= 0)
 | 
							rc = mgcp_udp_send_msg(rtp_end->rtp, &rtp_end->addr, msg);
 | 
				
			||||||
				return len;
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
							rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
			rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
							rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
				
			||||||
			rtp_state->alt_rtp_tx_sequence++;
 | 
							rtp_state->alt_rtp_tx_sequence++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			nbytes += len;
 | 
							return 0;
 | 
				
			||||||
			buflen = cont;
 | 
					 | 
				
			||||||
		} while (buflen > 0);
 | 
					 | 
				
			||||||
		return nbytes;
 | 
					 | 
				
			||||||
	} else if (!trunk->omit_rtcp) {
 | 
						} else if (!trunk->omit_rtcp) {
 | 
				
			||||||
		struct osmo_sockaddr rtcp_addr = rtp_end->addr;
 | 
							struct osmo_sockaddr rtcp_addr = rtp_end->addr;
 | 
				
			||||||
		osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
 | 
							osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(rtp_end->rtcp_port));
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
								 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
 | 
								 dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
 | 
				
			||||||
@@ -1265,19 +1255,54 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
			 osmo_sockaddr_port(&rtcp_addr.u.sa)
 | 
								 osmo_sockaddr_port(&rtcp_addr.u.sa)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
 | 
							len = msgb_length(msg);
 | 
				
			||||||
				    (char *)msgb_data(msg), msgb_length(msg));
 | 
					
 | 
				
			||||||
 | 
							rc = mgcp_udp_send_msg(rtp_end->rtcp, &rtcp_addr, msg);
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
							rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
		rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
							rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
				
			||||||
		rtp_state->alt_rtp_tx_sequence++;
 | 
							rtp_state->alt_rtp_tx_sequence++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return len;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! determine if there's only a single recipient in endp for data received via conn_src.
 | 
				
			||||||
 | 
					 *  The function returns NULL in case there is no recipient, or in case there are multiple recipients.
 | 
				
			||||||
 | 
					 *  \param endp The MGCP endpoint whose connections to analyze
 | 
				
			||||||
 | 
					 *  \param conn_src The source MGCP connection [which shall not count in results]
 | 
				
			||||||
 | 
					 *  \returns recipient donnection if there is only one; NULL in case there are multiple */
 | 
				
			||||||
 | 
					static struct mgcp_conn *rtpbridge_get_only_recipient(struct mgcp_endpoint *endp, struct mgcp_conn *conn_src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_ret = NULL;
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(conn_dst, &endp->conns, entry) {
 | 
				
			||||||
 | 
							if (conn_dst == conn_src)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							switch (conn_dst->mode) {
 | 
				
			||||||
 | 
							case MGCP_CONN_SEND_ONLY:
 | 
				
			||||||
 | 
							case MGCP_CONN_RECV_SEND:
 | 
				
			||||||
 | 
							case MGCP_CONN_CONFECHO:
 | 
				
			||||||
 | 
								if (conn_ret)
 | 
				
			||||||
 | 
									return NULL;
 | 
				
			||||||
 | 
								conn_ret = conn_dst;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return conn_ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dispatch incoming RTP packet to opposite RTP connection.
 | 
					/*! Dispatch incoming RTP packet to opposite RTP connection.
 | 
				
			||||||
 * \param[in] msg Message buffer to bridge, coming from source connection.
 | 
					 * \param[in] msg Message buffer to bridge, coming from source connection.
 | 
				
			||||||
 *            msg shall contain "struct osmo_rtp_msg_ctx *" attached in
 | 
					 *            msg shall contain "struct osmo_rtp_msg_ctx *" attached in
 | 
				
			||||||
@@ -1314,13 +1339,13 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
							if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn_src->end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn_src->end.addr));
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
									     osmo_sockaddr_port(&conn_src->end.addr.u.sa));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1335,23 +1360,44 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the mode is "confecho", send RTP back to the sender. */
 | 
						/* All the use cases above are 1:1 where we have one source msgb and we're sending that to one
 | 
				
			||||||
	if (conn->mode == MGCP_CONN_CONFECHO)
 | 
						 * destination.  msgb ownership had been passed to the respective _*dospatch_rtp() function.
 | 
				
			||||||
		rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
						 * In the cases below, we actually [can] have multiple recipients, so we copy the original msgb
 | 
				
			||||||
 | 
						 * for each of the recipients. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Dispatch RTP packet to all other connection(s) that send audio. */
 | 
						/* If the mode is "confecho", send RTP back to the sender. */
 | 
				
			||||||
	llist_for_each_entry(conn_dst, &endp->conns, entry) {
 | 
						if (conn->mode == MGCP_CONN_CONFECHO) {
 | 
				
			||||||
		if (conn_dst == conn)
 | 
							struct msgb *msg2 = mgw_msgb_copy_c(conn, msg, "RTP confecho");
 | 
				
			||||||
			continue;
 | 
							if (OSMO_LIKELY(msg2))
 | 
				
			||||||
		switch (conn_dst->mode) {
 | 
								rc = mgcp_conn_rtp_dispatch_rtp(conn_src, msg2);
 | 
				
			||||||
		case MGCP_CONN_SEND_ONLY:
 | 
						}
 | 
				
			||||||
		case MGCP_CONN_RECV_SEND:
 | 
					
 | 
				
			||||||
		case MGCP_CONN_CONFECHO:
 | 
						conn_dst = rtpbridge_get_only_recipient(endp, conn);
 | 
				
			||||||
			rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
						if (OSMO_LIKELY(conn_dst)) {
 | 
				
			||||||
			break;
 | 
							/* we only have a single recipient and cann hence send the original msgb without copying */
 | 
				
			||||||
		default:
 | 
							rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
				
			||||||
			break;
 | 
						} else {
 | 
				
			||||||
 | 
							/* Dispatch RTP packet to all other connection(s) that send audio. */
 | 
				
			||||||
 | 
							llist_for_each_entry(conn_dst, &endp->conns, entry) {
 | 
				
			||||||
 | 
								struct msgb *msg2;
 | 
				
			||||||
 | 
								if (conn_dst == conn)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								switch (conn_dst->mode) {
 | 
				
			||||||
 | 
								case MGCP_CONN_SEND_ONLY:
 | 
				
			||||||
 | 
								case MGCP_CONN_RECV_SEND:
 | 
				
			||||||
 | 
								case MGCP_CONN_CONFECHO:
 | 
				
			||||||
 | 
									/* we have multiple recipients and must make copies for each recipient */
 | 
				
			||||||
 | 
									msg2 = mgw_msgb_copy_c(conn_dst, msg, "RTP Tx copy");
 | 
				
			||||||
 | 
									if (OSMO_LIKELY(msg2))
 | 
				
			||||||
 | 
										rc = mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg2);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							/* as we only sent copies in the previous llist_for_each_entry() loop, we must free the
 | 
				
			||||||
 | 
							 * original one */
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1378,19 +1424,19 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
							if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn_src->end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn_src->end.addr));
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
									     osmo_sockaddr_port(&conn_src->end.addr.u.sa));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward to E1 */
 | 
						/* Forward to E1 */
 | 
				
			||||||
	return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
 | 
						return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
 | 
					/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
 | 
				
			||||||
@@ -1423,7 +1469,7 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Handle incoming RTP data from NET */
 | 
					/* Handle incoming RTP data from NET */
 | 
				
			||||||
static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
					static void rtp_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *saddr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* NOTE: This is a generic implementation. RTP data is received. In
 | 
						/* NOTE: This is a generic implementation. RTP data is received. In
 | 
				
			||||||
	 * case of loopback the data is just sent back to its origin. All
 | 
						 * case of loopback the data is just sent back to its origin. All
 | 
				
			||||||
@@ -1434,49 +1480,34 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_src;
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	struct osmo_sockaddr addr;
 | 
					 | 
				
			||||||
	socklen_t slen = sizeof(addr);
 | 
					 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
	enum rtp_proto proto;
 | 
						enum rtp_proto proto;
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc;
 | 
						struct osmo_rtp_msg_ctx *mc;
 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_src = (struct mgcp_conn_rtp *)fd->data;
 | 
						conn_src = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
 | 
				
			||||||
	OSMO_ASSERT(conn_src);
 | 
						OSMO_ASSERT(conn_src);
 | 
				
			||||||
	endp = conn_src->conn->endp;
 | 
						endp = conn_src->conn->endp;
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	proto = (fd == &conn_src->end.rtp)? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
 | 
						proto = (iofd == conn_src->end.rtp) ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = recvfrom(fd->fd, msgb_data(msg), msg->data_len, 0, (struct sockaddr *)&addr.u.sa, &slen);
 | 
						if (res <= 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(-res));
 | 
				
			||||||
	if (ret <= 0) {
 | 
							goto out_free;
 | 
				
			||||||
		LOG_CONN_RTP(conn_src, LOGL_ERROR, "recvfrom error: %s\n", strerror(errno));
 | 
					 | 
				
			||||||
		rc = -1;
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_put(msg, ret);
 | 
						LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s\n",
 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
 | 
					 | 
				
			||||||
		     proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
 | 
							     proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
 | 
				
			||||||
		     msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
 | 
							     msgb_length(msg), osmo_sockaddr_to_str(saddr));
 | 
				
			||||||
		     osmo_sockaddr_port(&addr.u.sa));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
 | 
						if ((proto == MGCP_PROTO_RTP && check_rtp(conn_src, msg))
 | 
				
			||||||
	    || (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
 | 
						    || (proto == MGCP_PROTO_RTCP && check_rtcp(conn_src, msg))) {
 | 
				
			||||||
		/* Logging happened in the two check_ functions */
 | 
							/* Logging happened in the two check_ functions */
 | 
				
			||||||
		rc = -1;
 | 
							goto out_free;
 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_is_rtp_dummy_payload(msg)) {
 | 
						if (mgcp_is_rtp_dummy_payload(msg)) {
 | 
				
			||||||
		LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
 | 
							LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx dummy packet (dropped)\n");
 | 
				
			||||||
		rc = 0;
 | 
							goto out_free;
 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
 | 
						/* Since the msgb remains owned and freed by this function, the msg ctx data struct can just be on the stack and
 | 
				
			||||||
@@ -1485,7 +1516,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
	*mc = (struct osmo_rtp_msg_ctx){
 | 
						*mc = (struct osmo_rtp_msg_ctx){
 | 
				
			||||||
		.proto = proto,
 | 
							.proto = proto,
 | 
				
			||||||
		.conn_src = conn_src,
 | 
							.conn_src = conn_src,
 | 
				
			||||||
		.from_addr = &addr,
 | 
							.from_addr = (struct osmo_sockaddr *) saddr,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
 | 
						LOG_CONN_RTP(conn_src, LOGL_DEBUG, "msg ctx: %d %p %s\n",
 | 
				
			||||||
		     mc->proto, mc->conn_src,
 | 
							     mc->proto, mc->conn_src,
 | 
				
			||||||
@@ -1500,16 +1531,17 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
	/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
						/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
	forward_data_tap(fd->fd, &conn_src->tap_in, msg);
 | 
						forward_data_tap(iofd, &conn_src->tap_in, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = rx_rtp(msg);
 | 
						rx_rtp(msg);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out_free:
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Note: This function is able to handle RTP and RTCP */
 | 
					/* Note: This function is able to handle RTP and RTCP. msgb ownership is transferred, so this function or its
 | 
				
			||||||
 | 
					 * downstream consumers must make sure to [eventually] free the msgb. */
 | 
				
			||||||
static int rx_rtp(struct msgb *msg)
 | 
					static int rx_rtp(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
@@ -1522,22 +1554,23 @@ static int rx_rtp(struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Check if the origin of the RTP packet seems plausible */
 | 
						/* Check if the origin of the RTP packet seems plausible */
 | 
				
			||||||
	if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
						if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
				
			||||||
		return -1;
 | 
							goto out_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
 | 
						/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
 | 
				
			||||||
	if (mc->proto == MGCP_PROTO_RTP &&
 | 
						if (mc->proto == MGCP_PROTO_RTP
 | 
				
			||||||
	    mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
 | 
						    && conn_src->end.cset.codec
 | 
				
			||||||
 | 
						    && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) {
 | 
				
			||||||
		/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
 | 
							/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
 | 
				
			||||||
		 * communicated via SDP when the connection was created/modfied. */
 | 
							 * communicated via SDP when the connection was created/modfied. */
 | 
				
			||||||
		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
							int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
		if (oa < 0)
 | 
							if (oa < 0)
 | 
				
			||||||
			return -1;
 | 
								goto out_free;
 | 
				
			||||||
		if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
 | 
							if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) {
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
 | 
									     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
 | 
				
			||||||
				     " check the config of your call-agent!\n",
 | 
									     " check the config of your call-agent!\n",
 | 
				
			||||||
				     msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
 | 
									     msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa);
 | 
				
			||||||
			return -1;
 | 
								goto out_free;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1546,17 +1579,36 @@ static int rx_rtp(struct msgb *msg)
 | 
				
			|||||||
	/* Execute endpoint specific implementation that handles the
 | 
						/* Execute endpoint specific implementation that handles the
 | 
				
			||||||
	 * dispatching of the RTP data */
 | 
						 * dispatching of the RTP data */
 | 
				
			||||||
	return conn->endp->type->dispatch_rtp_cb(msg);
 | 
						return conn->endp->type->dispatch_rtp_cb(msg);
 | 
				
			||||||
 | 
					out_free:
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rtp_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *daddr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* nothing; osmo_io takes care of msgb_free */
 | 
				
			||||||
 | 
						if (res < 0) {
 | 
				
			||||||
 | 
							struct mgcp_conn_rtp *conn_rtp = (struct mgcp_conn_rtp *) osmo_iofd_get_data(iofd);
 | 
				
			||||||
 | 
							int priv_nr = osmo_iofd_get_priv_nr(iofd);
 | 
				
			||||||
 | 
							char errbuf[129];
 | 
				
			||||||
 | 
							strerror_r(-res, errbuf, sizeof(errbuf));
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%s sendto(%s) failed: %s\n", priv_nr ? "RTCP" : "RTP",
 | 
				
			||||||
 | 
								 osmo_sockaddr_to_str(daddr), errbuf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_io_ops rtp_ioops = {
 | 
				
			||||||
 | 
						.recvfrom_cb = rtp_recvfrom_cb,
 | 
				
			||||||
 | 
						.sendto_cb = rtp_sendto_cb,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! bind RTP port to osmo_fd.
 | 
					/*! bind RTP port to osmo_fd.
 | 
				
			||||||
 *  \param[in] source_addr source (local) address to bind on.
 | 
					 *  \param[in] source_addr source (local) address to bind on.
 | 
				
			||||||
 *  \param[in] fd associated file descriptor.
 | 
					 | 
				
			||||||
 *  \param[in] port to bind on.
 | 
					 *  \param[in] port to bind on.
 | 
				
			||||||
 *  \param[in] dscp IP DSCP value to use.
 | 
					 *  \param[in] dscp IP DSCP value to use.
 | 
				
			||||||
 *  \param[in] prio socket priority to use.
 | 
					 *  \param[in] prio socket priority to use.
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
					 *  \returns file descriptor on success, -1 on ERROR. */
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
					int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio)
 | 
				
			||||||
		     uint8_t prio)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1564,85 +1616,32 @@ int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint
 | 
				
			|||||||
			     NULL, 0, OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(dscp) |
 | 
								     NULL, 0, OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(dscp) |
 | 
				
			||||||
			     OSMO_SOCK_F_PRIO(prio));
 | 
								     OSMO_SOCK_F_PRIO(prio));
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
 | 
							LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%d).\n",
 | 
				
			||||||
		     source_addr, port);
 | 
							     source_addr, port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	fd->fd = rc;
 | 
						LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%d).\n", source_addr, port);
 | 
				
			||||||
	LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
 | 
					 | 
				
			||||||
static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
 | 
					 | 
				
			||||||
		    struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* NOTE: The port that is used for RTCP is the RTP port incremented by one
 | 
					 | 
				
			||||||
	 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp_create_bind(source_addr, &rtp_end->rtp, rtp_end->local_port,
 | 
					 | 
				
			||||||
			     cfg->endp_dscp, cfg->endp_priority) != 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "failed to create RTP port: %s:%d\n",
 | 
					 | 
				
			||||||
			 source_addr, rtp_end->local_port);
 | 
					 | 
				
			||||||
		goto cleanup0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp_create_bind(source_addr, &rtp_end->rtcp, rtp_end->local_port + 1,
 | 
					 | 
				
			||||||
			     cfg->endp_dscp, cfg->endp_priority) != 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "failed to create RTCP port: %s:%d\n",
 | 
					 | 
				
			||||||
			 source_addr, rtp_end->local_port + 1);
 | 
					 | 
				
			||||||
		goto cleanup1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (osmo_fd_register(&rtp_end->rtp) != 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "failed to register RTP port %d\n",
 | 
					 | 
				
			||||||
			 rtp_end->local_port);
 | 
					 | 
				
			||||||
		goto cleanup2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (osmo_fd_register(&rtp_end->rtcp) != 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "failed to register RTCP port %d\n",
 | 
					 | 
				
			||||||
			 rtp_end->local_port + 1);
 | 
					 | 
				
			||||||
		goto cleanup3;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
cleanup3:
 | 
					 | 
				
			||||||
	osmo_fd_unregister(&rtp_end->rtp);
 | 
					 | 
				
			||||||
cleanup2:
 | 
					 | 
				
			||||||
	close(rtp_end->rtcp.fd);
 | 
					 | 
				
			||||||
	rtp_end->rtcp.fd = -1;
 | 
					 | 
				
			||||||
cleanup1:
 | 
					 | 
				
			||||||
	close(rtp_end->rtp.fd);
 | 
					 | 
				
			||||||
	rtp_end->rtp.fd = -1;
 | 
					 | 
				
			||||||
cleanup0:
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! bind RTP port to endpoint/connection.
 | 
					/*! bind RTP port to endpoint/connection.
 | 
				
			||||||
 *  \param[in] endp endpoint that holds the RTP connection.
 | 
					 | 
				
			||||||
 *  \param[in] rtp_port port number to bind on.
 | 
					 | 
				
			||||||
 *  \param[in] conn associated RTP connection.
 | 
					 *  \param[in] conn associated RTP connection.
 | 
				
			||||||
 | 
					 *  \param[in] rtp_port port number to bind on.
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
					int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port)
 | 
				
			||||||
			   struct mgcp_conn_rtp *conn)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char name[512];
 | 
						char name[512];
 | 
				
			||||||
	struct mgcp_rtp_end *end;
 | 
						struct mgcp_conn *conn = conn_rtp->conn;
 | 
				
			||||||
 | 
						struct mgcp_config *cfg = conn->endp->trunk->cfg;
 | 
				
			||||||
 | 
						struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
				
			||||||
 | 
						int rc, rtp_fd, rtcp_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
 | 
						snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id);
 | 
				
			||||||
	end = &conn->end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n",
 | 
					 | 
				
			||||||
			 rtp_port, mgcp_conn_dump(conn->conn));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) ||
 | 
				
			||||||
 | 
						    (end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%u was already bound\n", rtp_port);
 | 
				
			||||||
		/* Double bindings should never occour! Since we always allocate
 | 
							/* Double bindings should never occour! Since we always allocate
 | 
				
			||||||
		 * connections dynamically and free them when they are not
 | 
							 * connections dynamically and free them when they are not
 | 
				
			||||||
		 * needed anymore, there must be no previous binding leftover.
 | 
							 * needed anymore, there must be no previous binding leftover.
 | 
				
			||||||
@@ -1652,25 +1651,55 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	end->local_port = rtp_port;
 | 
						end->local_port = rtp_port;
 | 
				
			||||||
	osmo_fd_setup(&end->rtp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
 | 
						end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
 | 
				
			||||||
	osmo_fd_setup(&end->rtcp, -1, OSMO_FD_READ, rtp_data_net, conn, 0);
 | 
						if (!end->rtp)
 | 
				
			||||||
 | 
							goto free_iofd_ret;
 | 
				
			||||||
 | 
						osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0);
 | 
				
			||||||
 | 
						end->rtcp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp);
 | 
				
			||||||
 | 
						if (!end->rtcp)
 | 
				
			||||||
 | 
							goto free_iofd_ret;
 | 
				
			||||||
 | 
						osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0);
 | 
				
			||||||
 | 
						osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp);
 | 
						/* NOTE: The port that is used for RTCP is the RTP port incremented by one
 | 
				
			||||||
}
 | 
						 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! free allocated RTP and RTCP ports.
 | 
						rc = mgcp_create_bind(end->local_addr, end->local_port, cfg->endp_dscp, cfg->endp_priority);
 | 
				
			||||||
 *  \param[in] end RTP end */
 | 
						if (rc < 0) {
 | 
				
			||||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTP port: %s:%d\n", end->local_addr, end->local_port);
 | 
				
			||||||
{
 | 
							goto free_iofd_ret;
 | 
				
			||||||
	if (end->rtp.fd != -1) {
 | 
						}
 | 
				
			||||||
		osmo_fd_unregister(&end->rtp);
 | 
						rtp_fd = rc;
 | 
				
			||||||
		close(end->rtp.fd);
 | 
					
 | 
				
			||||||
		end->rtp.fd = -1;
 | 
						rc = mgcp_create_bind(end->local_addr, end->local_port + 1, cfg->endp_dscp, cfg->endp_priority);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTCP port: %s:%d\n", end->local_addr, end->local_port + 1);
 | 
				
			||||||
 | 
							goto cleanup1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rtcp_fd = rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmo_iofd_register(end->rtp, rtp_fd) < 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTP port %d\n", end->local_port);
 | 
				
			||||||
 | 
							goto cleanup2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (end->rtcp.fd != -1) {
 | 
						if (osmo_iofd_register(end->rtcp, rtcp_fd) != 0) {
 | 
				
			||||||
		osmo_fd_unregister(&end->rtcp);
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTCP port %d\n", end->local_port + 1);
 | 
				
			||||||
		close(end->rtcp.fd);
 | 
							goto cleanup3;
 | 
				
			||||||
		end->rtcp.fd = -1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup3:
 | 
				
			||||||
 | 
						osmo_iofd_unregister(end->rtp);
 | 
				
			||||||
 | 
					cleanup2:
 | 
				
			||||||
 | 
						close(rtcp_fd);
 | 
				
			||||||
 | 
					cleanup1:
 | 
				
			||||||
 | 
						close(rtp_fd);
 | 
				
			||||||
 | 
					free_iofd_ret:
 | 
				
			||||||
 | 
						osmo_iofd_free(end->rtcp);
 | 
				
			||||||
 | 
						end->rtcp = NULL;
 | 
				
			||||||
 | 
						osmo_iofd_free(end->rtp);
 | 
				
			||||||
 | 
						end->rtp = NULL;
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
 | 
					 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
 | 
				
			||||||
 * (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
 | 
					 * (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
 | 
				
			||||||
 | 
					 * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
 | 
				
			||||||
 * All rights not specifically granted under this license are reserved.
 | 
					 * All rights not specifically granted under this license are reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify it
 | 
					 * This program is free software; you can redistribute it and/or modify it
 | 
				
			||||||
@@ -13,9 +14,11 @@
 | 
				
			|||||||
#include <string.h> /* for memcpy */
 | 
					#include <string.h> /* for memcpy */
 | 
				
			||||||
#include <stdlib.h> /* for abs */
 | 
					#include <stdlib.h> /* for abs */
 | 
				
			||||||
#include <inttypes.h> /* for PRIu64 */
 | 
					#include <inttypes.h> /* for PRIu64 */
 | 
				
			||||||
 | 
					#include <unistd.h> /* for PRIu64 */
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
@@ -30,8 +33,8 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct osmo_fd osmux_fd_v4;
 | 
					static struct osmo_io_fd *osmux_fd_v4;
 | 
				
			||||||
static struct osmo_fd osmux_fd_v6;
 | 
					static struct osmo_io_fd *osmux_fd_v6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static LLIST_HEAD(osmux_handle_list);
 | 
					static LLIST_HEAD(osmux_handle_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,34 +79,31 @@ static void rtpconn_osmux_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, int id)
 | 
				
			|||||||
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
 | 
					static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmux_handle *handle = data;
 | 
						struct osmux_handle *handle = data;
 | 
				
			||||||
	socklen_t dest_len;
 | 
						int rc;
 | 
				
			||||||
	int rc, fd;
 | 
						struct osmo_io_fd *iofd;
 | 
				
			||||||
	struct mgcp_trunk *trunk = (struct mgcp_trunk *)osmux_fd_v4.data;
 | 
						struct mgcp_trunk *trunk = (struct mgcp_trunk *) osmo_iofd_get_data(osmux_fd_v4);
 | 
				
			||||||
	struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
 | 
						struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (handle->rem_addr.u.sa.sa_family) {
 | 
						switch (handle->rem_addr.u.sa.sa_family) {
 | 
				
			||||||
	case AF_INET6:
 | 
						case AF_INET6:
 | 
				
			||||||
		dest_len = sizeof(handle->rem_addr.u.sin6);
 | 
							iofd = osmux_fd_v6;
 | 
				
			||||||
		fd = osmux_fd_v6.fd;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case AF_INET:
 | 
						case AF_INET:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		dest_len = sizeof(handle->rem_addr.u.sin);
 | 
							iofd = osmux_fd_v4;
 | 
				
			||||||
		fd = osmux_fd_v4.fd;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc = sendto(fd, batch_msg->data, batch_msg->len, 0,
 | 
						rc = osmo_iofd_sendto_msgb(iofd, batch_msg, 0, &handle->rem_addr);
 | 
				
			||||||
		    (struct sockaddr *)&handle->rem_addr.u.sa, dest_len);
 | 
					 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		char errbuf[129];
 | 
							char errbuf[129];
 | 
				
			||||||
		strerror_r(errno, errbuf, sizeof(errbuf));
 | 
							strerror_r(-rc, errbuf, sizeof(errbuf));
 | 
				
			||||||
		LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n",
 | 
							LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n",
 | 
				
			||||||
			 osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
 | 
								 osmo_sockaddr_to_str(&handle->rem_addr), errbuf);
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
 | 
				
			||||||
 | 
							msgb_free(batch_msg);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_PACKETS_TX_CTR));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_PACKETS_TX_CTR));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msgb_free(batch_msg);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Lookup existing OSMUX handle for specified destination address. */
 | 
					/* Lookup existing OSMUX handle for specified destination address. */
 | 
				
			||||||
@@ -204,17 +204,17 @@ osmux_handle_find_or_create(const struct mgcp_trunk *trunk, const struct osmo_so
 | 
				
			|||||||
	return h->in;
 | 
						return h->in;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! send RTP packet through OSMUX connection.
 | 
					/*! send RTP packet through OSMUX connection. Takes ownership of msg.
 | 
				
			||||||
 *  \param[in] conn associated RTP connection
 | 
					 *  \param[in] conn associated RTP connection
 | 
				
			||||||
 *  \param[in] msg msgb containing an RTP AMR packet
 | 
					 *  \param[in] msg msgb containing an RTP AMR packet
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR */
 | 
					 *  \returns 0 on success, -1 on ERROR */
 | 
				
			||||||
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
 | 
					int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	struct msgb *msg2;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn->end.output_enabled) {
 | 
						if (!conn->end.output_enabled) {
 | 
				
			||||||
		rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
							rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -222,22 +222,19 @@ int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
 | 
				
			|||||||
		LOGPCONN(conn->conn, DOSMUX, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
 | 
							LOGPCONN(conn->conn, DOSMUX, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
 | 
				
			||||||
		conn->osmux.remote_cid);
 | 
							conn->osmux.remote_cid);
 | 
				
			||||||
		rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
							rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* msg is not owned by us and will be freed by the caller stack upon return: */
 | 
					 | 
				
			||||||
	msg2 = msgb_copy_c(conn->conn, msg, "osmux-rtp-send");
 | 
					 | 
				
			||||||
	if (!msg2)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Osmux implementation works with AMR OA only, make sure we convert to it if needed: */
 | 
						/* Osmux implementation works with AMR OA only, make sure we convert to it if needed: */
 | 
				
			||||||
	if (amr_oa_bwe_convert(conn->conn->endp, msg2, true) < 0) {
 | 
						if (amr_oa_bwe_convert(conn->conn->endp, msg, true) < 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
 | 
				
			||||||
			 "Error converting to AMR octet-aligned mode\n");
 | 
								 "Error converting to AMR octet-aligned mode\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ret = osmux_xfrm_input(conn->osmux.in, msg2, conn->osmux.remote_cid)) > 0) {
 | 
						while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.remote_cid)) > 0) {
 | 
				
			||||||
		/* batch full, build and deliver it */
 | 
							/* batch full, build and deliver it */
 | 
				
			||||||
		osmux_xfrm_input_deliver(conn->osmux.in);
 | 
							osmux_xfrm_input_deliver(conn->osmux.in);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -245,7 +242,7 @@ int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg)
 | 
				
			|||||||
		rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
							rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
 | 
							rtpconn_osmux_rate_ctr_inc(conn, OSMUX_RTP_PACKETS_TX_CTR);
 | 
				
			||||||
		rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg2) - sizeof(struct rtp_hdr));
 | 
							rtpconn_osmux_rate_ctr_add(conn, OSMUX_AMR_OCTETS_TX_CTR, msgb_length(msg) - sizeof(struct rtp_hdr));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -268,7 +265,7 @@ osmux_conn_lookup(const struct mgcp_trunk *trunk, uint8_t local_cid, const struc
 | 
				
			|||||||
			if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
								if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			conn_rtp = &conn->u.rtp;
 | 
								conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
			if (!mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
								if (!mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -325,29 +322,7 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endp->type->dispatch_rtp_cb(msg);
 | 
						endp->type->dispatch_rtp_cb(msg);
 | 
				
			||||||
	msgb_free(msg);
 | 
						/* dispatch_rtp_cb() has taken ownership of the msgb */
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct msgb *osmux_recv(struct osmo_fd *ofd, struct osmo_sockaddr *addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	socklen_t slen = sizeof(addr->u.sas);
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg = msgb_alloc(4096, "OSMUX");
 | 
					 | 
				
			||||||
	if (!msg) {
 | 
					 | 
				
			||||||
		LOGP(DOSMUX, LOGL_ERROR, "cannot allocate message\n");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0, &addr->u.sa, &slen);
 | 
					 | 
				
			||||||
	if (ret <= 0) {
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		LOGP(DOSMUX, LOGL_ERROR, "cannot receive message\n");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	msgb_put(msg, ret);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return msg;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* To be called every time some AMR data is received on a connection
 | 
					/* To be called every time some AMR data is received on a connection
 | 
				
			||||||
@@ -445,22 +420,16 @@ out:
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define osmux_chunk_length(msg, rem) ((rem) - (msg)->len)
 | 
					#define osmux_chunk_length(msg, rem) ((rem) - (msg)->len)
 | 
				
			||||||
static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
					static void osmux_recvfrom_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *rem_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	struct osmux_hdr *osmuxh;
 | 
						struct osmux_hdr *osmuxh;
 | 
				
			||||||
	struct osmo_sockaddr rem_addr;
 | 
						struct mgcp_trunk *trunk = osmo_iofd_get_data(iofd);
 | 
				
			||||||
	uint32_t rem;
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk = ofd->data;
 | 
					 | 
				
			||||||
	struct rate_ctr_group *all_rtp_stats = trunk->ratectr.all_osmux_conn_stats;
 | 
						struct rate_ctr_group *all_rtp_stats = trunk->ratectr.all_osmux_conn_stats;
 | 
				
			||||||
 | 
						uint32_t rem;
 | 
				
			||||||
	char addr_str[64];
 | 
						char addr_str[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = osmux_recv(ofd, &rem_addr);
 | 
					 | 
				
			||||||
	if (!msg)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(all_rtp_stats, OSMUX_PACKETS_RX_CTR));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(all_rtp_stats, OSMUX_PACKETS_RX_CTR));
 | 
				
			||||||
	osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), &rem_addr);
 | 
						osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), rem_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trunk->cfg->osmux.usage == OSMUX_USAGE_OFF) {
 | 
						if (trunk->cfg->osmux.usage == OSMUX_USAGE_OFF) {
 | 
				
			||||||
		LOGP(DOSMUX, LOGL_ERROR,
 | 
							LOGP(DOSMUX, LOGL_ERROR,
 | 
				
			||||||
@@ -470,14 +439,16 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Catch legacy dummy message and process them separately: */
 | 
						/* Catch legacy dummy message and process them separately: */
 | 
				
			||||||
	if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD)
 | 
						if (msg->len == 2 && msg->data[0] == MGCP_DUMMY_LOAD) {
 | 
				
			||||||
		return osmux_handle_legacy_dummy(trunk, &rem_addr, msg);
 | 
							osmux_handle_legacy_dummy(trunk, rem_addr, msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rem = msg->len;
 | 
						rem = msg->len;
 | 
				
			||||||
	while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 | 
						while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 | 
				
			||||||
		struct mgcp_conn_rtp *conn_src;
 | 
							struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
		conn_src = osmux_conn_lookup(trunk, osmuxh->circuit_id,
 | 
							conn_src = osmux_conn_lookup(trunk, osmuxh->circuit_id,
 | 
				
			||||||
					     &rem_addr);
 | 
										     rem_addr);
 | 
				
			||||||
		if (!conn_src) {
 | 
							if (!conn_src) {
 | 
				
			||||||
			LOGP(DOSMUX, LOGL_DEBUG,
 | 
								LOGP(DOSMUX, LOGL_DEBUG,
 | 
				
			||||||
			     "Cannot find a src conn for %s CID=%d\n",
 | 
								     "Cannot find a src conn for %s CID=%d\n",
 | 
				
			||||||
@@ -485,7 +456,7 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			|||||||
			goto next;
 | 
								goto next;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn_osmux_event_data_received(conn_src, &rem_addr) < 0)
 | 
							if (conn_osmux_event_data_received(conn_src, rem_addr) < 0)
 | 
				
			||||||
			goto next;
 | 
								goto next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgcp_conn_watchdog_kick(conn_src->conn);
 | 
							mgcp_conn_watchdog_kick(conn_src->conn);
 | 
				
			||||||
@@ -499,58 +470,94 @@ next:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmux_sendto_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg, const struct osmo_sockaddr *rem_addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* nothing; osmo_io takes care of msgb_free */
 | 
				
			||||||
 | 
						if (res < 0) {
 | 
				
			||||||
 | 
							struct mgcp_trunk *trunk = (struct mgcp_trunk *) osmo_iofd_get_data(iofd);
 | 
				
			||||||
 | 
							struct rate_ctr_group *all_osmux_stats = trunk->ratectr.all_osmux_conn_stats;
 | 
				
			||||||
 | 
							char errbuf[129];
 | 
				
			||||||
 | 
							strerror_r(-res, errbuf, sizeof(errbuf));
 | 
				
			||||||
 | 
							LOGP(DOSMUX, LOGL_NOTICE, "osmux sendto(%s) failed: %s\n", osmo_sockaddr_to_str(rem_addr), errbuf);
 | 
				
			||||||
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(all_osmux_stats, OSMUX_DROPPED_PACKETS_CTR));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_io_ops osmux_ioops = {
 | 
				
			||||||
 | 
						.recvfrom_cb = osmux_recvfrom_cb,
 | 
				
			||||||
 | 
						.sendto_cb = osmux_sendto_cb,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int osmux_init(struct mgcp_trunk *trunk)
 | 
					int osmux_init(struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret, fd;
 | 
				
			||||||
	struct mgcp_config *cfg = trunk->cfg;
 | 
						struct mgcp_config *cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* So far we only support running on one trunk: */
 | 
						/* So far we only support running on one trunk: */
 | 
				
			||||||
	OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
 | 
						OSMO_ASSERT(trunk == mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fd_setup(&osmux_fd_v4, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
 | 
						osmux_fd_v4 = osmo_iofd_setup(trunk, -1, "osmux_fd_v4", OSMO_IO_FD_MODE_RECVFROM_SENDTO, &osmux_ioops, trunk);
 | 
				
			||||||
	osmo_fd_setup(&osmux_fd_v6, -1, OSMO_FD_READ, osmux_read_fd_cb, trunk, 0);
 | 
						if (!osmux_fd_v4)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						osmo_iofd_set_alloc_info(osmux_fd_v4, 4096, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cfg->osmux.local_addr_v4) {
 | 
						if (cfg->osmux.local_addr_v4) {
 | 
				
			||||||
		ret = mgcp_create_bind(cfg->osmux.local_addr_v4, &osmux_fd_v4, cfg->osmux.local_port,
 | 
							ret = mgcp_create_bind(cfg->osmux.local_addr_v4, cfg->osmux.local_port,
 | 
				
			||||||
					cfg->endp_dscp, cfg->endp_priority);
 | 
										cfg->endp_dscp, cfg->endp_priority);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
 | 
								LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv4 socket to %s:%u\n",
 | 
				
			||||||
			     cfg->osmux.local_addr_v4, cfg->osmux.local_port);
 | 
								     cfg->osmux.local_addr_v4, cfg->osmux.local_port);
 | 
				
			||||||
			return ret;
 | 
								goto out_free_v4;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							fd = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = osmo_fd_register(&osmux_fd_v4);
 | 
							ret = osmo_iofd_register(osmux_fd_v4, fd);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n",
 | 
								LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv4 socket %s\n", osmo_sock_get_name2(fd));
 | 
				
			||||||
			     osmo_sock_get_name2(osmux_fd_v4.fd));
 | 
								close(fd);
 | 
				
			||||||
			return ret;
 | 
								goto out_free_v4;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n",
 | 
							LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv4 socket listening on %s\n", osmo_sock_get_name2(fd));
 | 
				
			||||||
		     osmo_sock_get_name2(osmux_fd_v4.fd));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmux_fd_v6 = osmo_iofd_setup(trunk, -1, "osmux_fd_v6", OSMO_IO_FD_MODE_RECVFROM_SENDTO, &osmux_ioops, trunk);
 | 
				
			||||||
 | 
						if (!osmux_fd_v6)
 | 
				
			||||||
 | 
							goto out_free_v4;
 | 
				
			||||||
 | 
						osmo_iofd_set_alloc_info(osmux_fd_v6, 4096, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cfg->osmux.local_addr_v6) {
 | 
						if (cfg->osmux.local_addr_v6) {
 | 
				
			||||||
		ret = mgcp_create_bind(cfg->osmux.local_addr_v6, &osmux_fd_v6, cfg->osmux.local_port,
 | 
							ret = mgcp_create_bind(cfg->osmux.local_addr_v6, cfg->osmux.local_port,
 | 
				
			||||||
					cfg->endp_dscp, cfg->endp_priority);
 | 
										cfg->endp_dscp, cfg->endp_priority);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
 | 
								LOGP(DOSMUX, LOGL_ERROR, "Cannot bind OSMUX IPv6 socket to [%s]:%u\n",
 | 
				
			||||||
			     cfg->osmux.local_addr_v6, cfg->osmux.local_port);
 | 
								     cfg->osmux.local_addr_v6, cfg->osmux.local_port);
 | 
				
			||||||
			return ret;
 | 
								goto out_free_v6;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							fd = ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = osmo_fd_register(&osmux_fd_v6);
 | 
							ret = osmo_iofd_register(osmux_fd_v6, fd);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n",
 | 
								LOGP(DOSMUX, LOGL_ERROR, "Cannot register OSMUX IPv6 socket %s\n", osmo_sock_get_name2(fd));
 | 
				
			||||||
			     osmo_sock_get_name2(osmux_fd_v6.fd));
 | 
								close(fd);
 | 
				
			||||||
			return ret;
 | 
								goto out_free_v6;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n",
 | 
							LOGP(DOSMUX, LOGL_INFO, "OSMUX IPv6 socket listening on %s\n", osmo_sock_get_name2(fd));
 | 
				
			||||||
		     osmo_sock_get_name2(osmux_fd_v6.fd));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cfg->osmux.initialized = true;
 | 
						cfg->osmux.initialized = true;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_free_v6:
 | 
				
			||||||
 | 
						/* osmo_iofd_free performs unregister + close */
 | 
				
			||||||
 | 
						osmo_iofd_free(osmux_fd_v6);
 | 
				
			||||||
 | 
						osmux_fd_v6 = NULL;
 | 
				
			||||||
 | 
					out_free_v4:
 | 
				
			||||||
 | 
						/* osmo_iofd_free performs unregister + close */
 | 
				
			||||||
 | 
						osmo_iofd_free(osmux_fd_v4);
 | 
				
			||||||
 | 
						osmux_fd_v4 = NULL;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! relase OSXMUX cid, that had been allocated to this connection.
 | 
					/*! relase OSXMUX cid, that had been allocated to this connection.
 | 
				
			||||||
@@ -644,7 +651,7 @@ int conn_osmux_enable(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
 | 
						osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out,
 | 
				
			||||||
				       (conn->osmux.remote_cid * rtp_ssrc_winlen) +
 | 
									       (conn->osmux.remote_cid * rtp_ssrc_winlen) +
 | 
				
			||||||
				       (random() % rtp_ssrc_winlen));
 | 
									       (random() % rtp_ssrc_winlen));
 | 
				
			||||||
	osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.codec->payload_type);
 | 
						osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type);
 | 
				
			||||||
	osmux_xfrm_output_set_tx_cb(conn->osmux.out,
 | 
						osmux_xfrm_output_set_tx_cb(conn->osmux.out,
 | 
				
			||||||
				    scheduled_from_osmux_tx_rtp_cb, conn);
 | 
									    scheduled_from_osmux_tx_rtp_cb, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -688,7 +695,7 @@ void conn_osmux_disable(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! send RTP dummy packet to OSMUX connection port.
 | 
					/*! send RTP dummy packet to OSMUX connection port.
 | 
				
			||||||
 *  \param[in] conn associated RTP connection
 | 
					 *  \param[in] conn associated RTP connection
 | 
				
			||||||
 *  \returns bytes sent, -1 on error */
 | 
					 *  \returns 0 in case of success, -1 on error */
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_conn_rtp *conn)
 | 
					int osmux_send_dummy(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
@@ -716,7 +723,7 @@ int osmux_send_dummy(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
 | 
							 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
 | 
				
			||||||
		 osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid);
 | 
							 osmo_sockaddr_port(&conn->end.addr.u.sa), conn->osmux.remote_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_udp_send(osmux_fd_v4.fd, &conn->end.addr, (char *)osmuxh, buf_len);
 | 
						return mgcp_udp_send(osmux_fd_v4, &conn->end.addr, (char *)osmuxh, buf_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Keeps track of locally allocated Osmux circuit ID. +7 to round up to 8 bit boundary. */
 | 
					/* Keeps track of locally allocated Osmux circuit ID. +7 to round up to 8 bit boundary. */
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by On-Waves
 | 
				
			||||||
 | 
					 * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********************
 | 
				
			||||||
 | 
					 * mgcp_rtp_end
 | 
				
			||||||
 | 
					 **********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk;
 | 
				
			||||||
 | 
						struct mgcp_config *cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end->conn_rtp = conn_rtp;
 | 
				
			||||||
 | 
						end->rtp = NULL;
 | 
				
			||||||
 | 
						end->rtcp = NULL;
 | 
				
			||||||
 | 
						memset(&end->addr, 0, sizeof(end->addr));
 | 
				
			||||||
 | 
						end->rtcp_port = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set default values */
 | 
				
			||||||
 | 
						end->frames_per_packet = 0;	/* unknown */
 | 
				
			||||||
 | 
						end->output_enabled = false;
 | 
				
			||||||
 | 
						end->maximum_packet_time = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end->force_aligned_timing = trunk->force_aligned_timing;
 | 
				
			||||||
 | 
						end->force_constant_ssrc = trunk->force_constant_ssrc;
 | 
				
			||||||
 | 
						end->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->force_ptime) {
 | 
				
			||||||
 | 
							end->packet_duration_ms = cfg->force_ptime;
 | 
				
			||||||
 | 
							end->force_output_ptime = 1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&end->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mgcp_rtp_end_free_port(end);
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&end->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (end->force_output_ptime)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						end->packet_duration_ms = packet_duration_ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
				
			||||||
 | 
						       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free allocated RTP and RTCP ports.
 | 
				
			||||||
 | 
					 *  \param[in] end RTP end */
 | 
				
			||||||
 | 
					void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (end->rtp) {
 | 
				
			||||||
 | 
							osmo_iofd_free(end->rtp);
 | 
				
			||||||
 | 
							end->rtp = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (end->rtcp) {
 | 
				
			||||||
 | 
							osmo_iofd_free(end->rtcp);
 | 
				
			||||||
 | 
							end->rtcp = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -312,16 +312,13 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze SDP input string.
 | 
					/*! Analyze SDP input string.
 | 
				
			||||||
 *  \param[in] endp trunk endpoint.
 | 
					 *  \param[inout] p provided memory to store the parsing results.
 | 
				
			||||||
 *  \param[out] conn associated rtp connection.
 | 
					 | 
				
			||||||
 *  \param[out] caller provided memory to store the parsing results.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Note: In conn (conn->end) the function returns the packet duration,
 | 
					 | 
				
			||||||
 *  rtp port, rtcp port and the codec information.
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -1 on failure. */
 | 
					 *  \returns 0 on success, -1 on failure. */
 | 
				
			||||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
					int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
 | 
				
			||||||
			struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(p);
 | 
				
			||||||
 | 
						struct mgcp_parse_sdp *sdp = &p->sdp;
 | 
				
			||||||
	struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
						struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int codecs_used = 0;
 | 
						unsigned int codecs_used = 0;
 | 
				
			||||||
	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
						struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
				
			||||||
@@ -331,19 +328,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	int ptime, ptime2 = 0;
 | 
						int ptime, ptime2 = 0;
 | 
				
			||||||
	char audio_name[64];
 | 
						char audio_name[64];
 | 
				
			||||||
	int port, rc;
 | 
						int port, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtp = &conn->end;
 | 
					 | 
				
			||||||
	memset(&codecs, 0, sizeof(codecs));
 | 
						memset(&codecs, 0, sizeof(codecs));
 | 
				
			||||||
 | 
						mgcp_parse_sdp_init(sdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (line[0]) {
 | 
				
			||||||
@@ -361,19 +353,19 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
								if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
				
			||||||
				if (ptime2 > 0 && ptime2 != ptime)
 | 
									if (ptime2 > 0 && ptime2 != ptime)
 | 
				
			||||||
					rtp->packet_duration_ms = 0;
 | 
										sdp->ptime = 0;
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					rtp->packet_duration_ms = ptime;
 | 
										sdp->ptime = ptime;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
								if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
				
			||||||
				rtp->maximum_packet_time = ptime2;
 | 
									sdp->maxptime = ptime2;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
								if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
				
			||||||
				rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
 | 
									rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
 | 
				
			||||||
				if (rc >= 0)
 | 
									if (rc >= 0)
 | 
				
			||||||
					fmtp_used++;
 | 
										fmtp_used++;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
@@ -382,33 +374,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'm':
 | 
							case 'm':
 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
				
			||||||
			if (rc == 1) {
 | 
								if (rc == 1)
 | 
				
			||||||
				osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
 | 
									sdp->rtp_port = port;
 | 
				
			||||||
				rtp->rtcp_port = htons(port + 1);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			rc = pt_from_sdp(conn->conn, codecs,
 | 
								rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
 | 
				
			||||||
					 ARRAY_SIZE(codecs), line);
 | 
					 | 
				
			||||||
			if (rc > 0)
 | 
								if (rc > 0)
 | 
				
			||||||
				codecs_used = rc;
 | 
									codecs_used = rc;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'c':
 | 
							case 'c':
 | 
				
			||||||
			if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
 | 
								if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
 | 
				
			||||||
				talloc_free(tmp_ctx);
 | 
									talloc_free(tmp_ctx);
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if (endp)
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
				/* TODO: Check spec: We used the bare endpoint number before,
 | 
								     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
				
			||||||
				 * now we use the endpoint name as a whole? Is this allowed? */
 | 
								     line[0], line[0], p->epname);
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
					 | 
				
			||||||
				     line[0], line[0], endp->name);
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d\n",
 | 
					 | 
				
			||||||
				     line[0], line[0]);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -422,23 +404,22 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	/* Store parsed codec information */
 | 
						/* Store parsed codec information */
 | 
				
			||||||
	for (i = 0; i < codecs_used; i++) {
 | 
						for (i = 0; i < codecs_used; i++) {
 | 
				
			||||||
		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
							codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
				
			||||||
		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
							rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
 | 
								LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(tmp_ctx);
 | 
						talloc_free(tmp_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
						     "%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
				
			||||||
	     osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
						     p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
 | 
				
			||||||
	     rtp->packet_duration_ms);
 | 
					 | 
				
			||||||
	if (codecs_used == 0)
 | 
						if (codecs_used == 0)
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
				
			||||||
	for (i = 0; i < codecs_used; i++) {
 | 
						for (i = 0; i < codecs_used; i++) {
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
 | 
				
			||||||
		      rtp->codecs[i].payload_type,
 | 
							      sdp->cset.codecs[i].payload_type,
 | 
				
			||||||
		      strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
 | 
							      strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
						LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
				
			||||||
@@ -488,34 +469,10 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Add fmtp strings to sdp payload */
 | 
					/* Add fmtp strings to sdp payload */
 | 
				
			||||||
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
 | 
					static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
 | 
				
			||||||
		    const char *fmtp_extra)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	int fmtp_extra_pt = -1;
 | 
					 | 
				
			||||||
	char *fmtp_extra_pars = "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When no fmtp parameters ara available but an fmtp extra string
 | 
					 | 
				
			||||||
	 * is configured, just add the fmtp extra string */
 | 
					 | 
				
			||||||
	if (fmtp_params_len == 0 && fmtp_extra) {
 | 
					 | 
				
			||||||
		return msgb_printf(sdp, "%s\r\n", fmtp_extra);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When there is fmtp extra configured we dissect it in order to drop
 | 
					 | 
				
			||||||
	 * in the configured extra parameters at the right place when
 | 
					 | 
				
			||||||
	 * generating the fmtp strings. */
 | 
					 | 
				
			||||||
	if (fmtp_extra) {
 | 
					 | 
				
			||||||
		if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
 | 
					 | 
				
			||||||
			fmtp_extra_pt = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		fmtp_extra_pars = strstr(fmtp_extra, " ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!fmtp_extra_pars)
 | 
					 | 
				
			||||||
			fmtp_extra_pars = "";
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			fmtp_extra_pars++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < fmtp_params_len; i++) {
 | 
						for (i = 0; i < fmtp_params_len; i++) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
							rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
				
			||||||
@@ -532,13 +489,6 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
 | 
				
			|||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Append extra parameters from fmtp extra */
 | 
					 | 
				
			||||||
		if (fmtp_params[i].payload_type == fmtp_extra_pt) {
 | 
					 | 
				
			||||||
			rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
 | 
					 | 
				
			||||||
			if (rc < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rc = msgb_printf(sdp, "\r\n");
 | 
							rc = msgb_printf(sdp, "\r\n");
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
@@ -558,7 +508,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			    const char *addr)
 | 
								    const char *addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct mgcp_rtp_codec *codec;
 | 
						const struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	const char *fmtp_extra;
 | 
					 | 
				
			||||||
	const char *audio_name;
 | 
						const char *audio_name;
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	struct sdp_fmtp_param fmtp_param;
 | 
						struct sdp_fmtp_param fmtp_param;
 | 
				
			||||||
@@ -574,10 +523,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	OSMO_ASSERT(sdp);
 | 
						OSMO_ASSERT(sdp);
 | 
				
			||||||
	OSMO_ASSERT(addr);
 | 
						OSMO_ASSERT(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
						codec = conn->end.cset.codec;
 | 
				
			||||||
	endp->trunk->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
					 | 
				
			||||||
					      &codec, &fmtp_extra,
 | 
					 | 
				
			||||||
					      (struct mgcp_conn_rtp *)conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_name = codec->audio_name;
 | 
						audio_name = codec->audio_name;
 | 
				
			||||||
	payload_type = codec->payload_type;
 | 
						payload_type = codec->payload_type;
 | 
				
			||||||
@@ -619,7 +565,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			fmtp_params[0] = fmtp_param;
 | 
								fmtp_params[0] = fmtp_param;
 | 
				
			||||||
			fmtp_params_len = 1;
 | 
								fmtp_params_len = 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
 | 
							rc = add_fmtp(sdp, fmtp_params, fmtp_params_len);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
 | 
				
			|||||||
	 * keep this option open: */
 | 
						 * keep this option open: */
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
 | 
							mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -306,3 +306,43 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Try to find a free port by attempting to bind on it. Also handle the
 | 
				
			||||||
 | 
					 * counter that points on the next free port. Since we have a pointer
 | 
				
			||||||
 | 
					 * to the next free port, binding should in work on the first attempt in
 | 
				
			||||||
 | 
					 * general. In case of failure the next port is tried until the whole port
 | 
				
			||||||
 | 
					 * range is tried once. */
 | 
				
			||||||
 | 
					int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct mgcp_port_range *range;
 | 
				
			||||||
 | 
						unsigned int tries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						range = &trunk->cfg->net_ports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pthread_mutex_lock(&range->lock);
 | 
				
			||||||
 | 
						/* attempt to find a port */
 | 
				
			||||||
 | 
						tries = (range->range_end - range->range_start) / 2;
 | 
				
			||||||
 | 
						for (i = 0; i < tries; ++i) {
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (range->last_port >= range->range_end)
 | 
				
			||||||
 | 
								range->last_port = range->range_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							range->last_port += 2;
 | 
				
			||||||
 | 
							if (rc == 0) {
 | 
				
			||||||
 | 
								pthread_mutex_unlock(&range->lock);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&range->lock);
 | 
				
			||||||
 | 
						LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							 "Allocating a RTP/RTCP port failed %u times.\n", tries);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,9 +111,6 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
 | 
							vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
	if (trunk->audio_fmtp_extra)
 | 
					 | 
				
			||||||
		vty_out(vty, " sdp audio fmtp-extra %s%s",
 | 
					 | 
				
			||||||
			trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	vty_out(vty, " %ssdp audio-payload send-ptime%s",
 | 
						vty_out(vty, " %ssdp audio-payload send-ptime%s",
 | 
				
			||||||
		trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 | 
							trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " %ssdp audio-payload send-name%s",
 | 
						vty_out(vty, " %ssdp audio-payload send-name%s",
 | 
				
			||||||
@@ -168,7 +165,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
						struct mgcp_rtp_state *state = &conn->state;
 | 
				
			||||||
	struct mgcp_rtp_end *end = &conn->end;
 | 
						struct mgcp_rtp_end *end = &conn->end;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec = end->codec;
 | 
						struct mgcp_rtp_codec *codec = end->cset.codec;
 | 
				
			||||||
	struct rate_ctr *tx_packets, *tx_bytes;
 | 
						struct rate_ctr *tx_packets, *tx_bytes;
 | 
				
			||||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
						struct rate_ctr *rx_packets, *rx_bytes;
 | 
				
			||||||
	struct rate_ctr *dropped_packets;
 | 
						struct rate_ctr *dropped_packets;
 | 
				
			||||||
@@ -187,7 +184,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		"   Payload Type: %d Rate: %u Channels: %d %s"
 | 
							"   Payload Type: %d Rate: %u Channels: %d %s"
 | 
				
			||||||
		"   Frame Duration: %u Frame Denominator: %u%s"
 | 
							"   Frame Duration: %u Frame Denominator: %u%s"
 | 
				
			||||||
		"   FPP: %d Packet Duration: %u%s"
 | 
							"   FPP: %d Packet Duration: %u%s"
 | 
				
			||||||
		"   FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
 | 
							"   Audio-Name: %s Sub-Type: %s%s"
 | 
				
			||||||
		"   Output-Enabled: %d Force-PTIME: %d%s",
 | 
							"   Output-Enabled: %d Force-PTIME: %d%s",
 | 
				
			||||||
		tx_packets->current, tx_bytes->current, VTY_NEWLINE,
 | 
							tx_packets->current, tx_bytes->current, VTY_NEWLINE,
 | 
				
			||||||
		rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
							rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
				
			||||||
@@ -198,7 +195,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
							codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
				
			||||||
		codec->frame_duration_num, codec->frame_duration_den,
 | 
							codec->frame_duration_num, codec->frame_duration_den,
 | 
				
			||||||
		VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
 | 
							VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
 | 
				
			||||||
		VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
							VTY_NEWLINE, codec->audio_name,
 | 
				
			||||||
		codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
							codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
				
			||||||
		end->force_output_ptime, VTY_NEWLINE);
 | 
							end->force_output_ptime, VTY_NEWLINE);
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
@@ -257,7 +254,8 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			|||||||
			 * connection types (E1) as soon as
 | 
								 * connection types (E1) as soon as
 | 
				
			||||||
			 * the implementation is available */
 | 
								 * the implementation is available */
 | 
				
			||||||
			if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
								if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
				dump_rtp_end(vty, &conn->u.rtp);
 | 
									struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
									dump_rtp_end(vty, conn_rtp);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -681,21 +679,15 @@ DEFUN_USRATTR(cfg_mgcp_no_rtp_force_ptime,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
 | 
					#define SDP_STR "SDP File related options\n"
 | 
				
			||||||
	      cfg_mgcp_sdp_fmtp_extra_cmd,
 | 
					#define AUDIO_STR "Audio payload options\n"
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "sdp audio fmtp-extra .NAME",
 | 
					 | 
				
			||||||
	      "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
 | 
					 | 
				
			||||||
	      "Extra Information\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
					 | 
				
			||||||
	char *txt = argv_concat(argv, argc, 0);
 | 
					 | 
				
			||||||
	if (!txt)
 | 
					 | 
				
			||||||
		return CMD_WARNING;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
 | 
					DEFUN_DEPRECATED(cfg_mgcp_sdp_fmtp_extra,
 | 
				
			||||||
	talloc_free(txt);
 | 
						      cfg_mgcp_sdp_fmtp_extra_cmd,
 | 
				
			||||||
 | 
						      "sdp audio fmtp-extra .NAME",
 | 
				
			||||||
 | 
						      SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -715,8 +707,6 @@ DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SDP_STR "SDP File related options\n"
 | 
					 | 
				
			||||||
#define AUDIO_STR "Audio payload options\n"
 | 
					 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
 | 
					DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
 | 
				
			||||||
      cfg_mgcp_sdp_payload_number_cmd,
 | 
					      cfg_mgcp_sdp_payload_number_cmd,
 | 
				
			||||||
      "sdp audio-payload number <0-255>",
 | 
					      "sdp audio-payload number <0-255>",
 | 
				
			||||||
@@ -867,7 +857,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 1;
 | 
						trunk->force_constant_ssrc = true;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -878,7 +868,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -933,7 +923,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	trunk->force_aligned_timing = 0;
 | 
						trunk->force_aligned_timing = 0;
 | 
				
			||||||
	trunk->rfc5993_hr_convert = false;
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -1062,28 +1052,17 @@ static int config_write_trunk(struct vty *vty)
 | 
				
			|||||||
				VTY_NEWLINE);
 | 
									VTY_NEWLINE);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
								vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
		if (trunk->audio_fmtp_extra)
 | 
					 | 
				
			||||||
			vty_out(vty, "   sdp audio fmtp-extra %s%s",
 | 
					 | 
				
			||||||
				trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_trunk_sdp_fmtp_extra,
 | 
					DEFUN_DEPRECATED(cfg_trunk_sdp_fmtp_extra,
 | 
				
			||||||
	      cfg_trunk_sdp_fmtp_extra_cmd,
 | 
						      cfg_trunk_sdp_fmtp_extra_cmd,
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "sdp audio fmtp-extra .NAME",
 | 
						      "sdp audio fmtp-extra .NAME",
 | 
				
			||||||
	      "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
 | 
						      SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
 | 
				
			||||||
	      "Extra Information\n")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
 | 
				
			||||||
	char *txt = argv_concat(argv, argc, 0);
 | 
					 | 
				
			||||||
	if (!txt)
 | 
					 | 
				
			||||||
		return CMD_WARNING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
 | 
					 | 
				
			||||||
	talloc_free(txt);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1218,7 +1197,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc,
 | 
				
			|||||||
	      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
						      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 1;
 | 
						trunk->force_constant_ssrc = true;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1228,7 +1207,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc,
 | 
				
			|||||||
	      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
						      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1278,7 +1257,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp,
 | 
				
			|||||||
	      "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
						      "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	trunk->force_aligned_timing = 0;
 | 
						trunk->force_aligned_timing = 0;
 | 
				
			||||||
	trunk->rfc5993_hr_convert = false;
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -1379,10 +1358,11 @@ DEFUN(loop_conn,
 | 
				
			|||||||
	endp = trunk->endpoints[endp_no];
 | 
						endp = trunk->endpoints[endp_no];
 | 
				
			||||||
	int loop = atoi(argv[2]);
 | 
						int loop = atoi(argv[2]);
 | 
				
			||||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
						llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
		if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
							if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
			/* Handle it like a MDCX, switch on SSRC patching if enabled */
 | 
								/* Handle it like a MDCX, switch on SSRC patching if enabled */
 | 
				
			||||||
			mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end);
 | 
								struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		else {
 | 
								conn_rtp->state.patch.patch_ssrc = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			/* FIXME: Introduce support for other connection (E1)
 | 
								/* FIXME: Introduce support for other connection (E1)
 | 
				
			||||||
			 * types when implementation is available */
 | 
								 * types when implementation is available */
 | 
				
			||||||
			vty_out(vty, "%%Can't enable SSRC patching,"
 | 
								vty_out(vty, "%%Can't enable SSRC patching,"
 | 
				
			||||||
@@ -1440,7 +1420,7 @@ DEFUN(tap_rtp,
 | 
				
			|||||||
	endp = trunk->endpoints[endp_no];
 | 
						endp = trunk->endpoints[endp_no];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_id = argv[2];
 | 
						conn_id = argv[2];
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn) {
 | 
				
			||||||
		vty_out(vty, "Conn ID %s is invalid.%s",
 | 
							vty_out(vty, "Conn ID %s is invalid.%s",
 | 
				
			||||||
			conn_id, VTY_NEWLINE);
 | 
								conn_id, VTY_NEWLINE);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -280,6 +280,31 @@ int mgcp_vty_go_parent(struct vty *vty)
 | 
				
			|||||||
	return vty->node;
 | 
						return vty->node;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void signal_handler(int signum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stdout, "signal %u received\n", signum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (signum) {
 | 
				
			||||||
 | 
						case SIGABRT:
 | 
				
			||||||
 | 
							/* in case of abort, we want to obtain a talloc report and
 | 
				
			||||||
 | 
							 * then run default SIGABRT handler, who will generate coredump
 | 
				
			||||||
 | 
							 * and abort the process. abort() should do this for us after we
 | 
				
			||||||
 | 
							 * return, but program wouldn't exit if an external SIGABRT is
 | 
				
			||||||
 | 
							 * received.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_mgw_ctx, stderr);
 | 
				
			||||||
 | 
							signal(SIGABRT, SIG_DFL);
 | 
				
			||||||
 | 
							raise(SIGABRT);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGUSR1:
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_mgw_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct vty_app_info vty_info = {
 | 
					static struct vty_app_info vty_info = {
 | 
				
			||||||
	.name 		= "OsmoMGW",
 | 
						.name 		= "OsmoMGW",
 | 
				
			||||||
@@ -328,6 +353,8 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	msgb_talloc_ctx_init(tall_mgw_ctx, 0);
 | 
						msgb_talloc_ctx_init(tall_mgw_ctx, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						signal(SIGABRT, &signal_handler);
 | 
				
			||||||
 | 
						signal(SIGUSR1, &signal_handler);
 | 
				
			||||||
	osmo_init_ignore_signals();
 | 
						osmo_init_ignore_signals();
 | 
				
			||||||
	osmo_init_logging2(tall_mgw_ctx, &log_info);
 | 
						osmo_init_logging2(tall_mgw_ctx, &log_info);
 | 
				
			||||||
	libosmo_abis_init(tall_mgw_ctx);
 | 
						libosmo_abis_init(tall_mgw_ctx);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,3 +45,6 @@ mgcp_test_LDADD = \
 | 
				
			|||||||
	$(LIBOSMONETIF_LIBS) \
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
	-lm  \
 | 
						-lm  \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update_exp:
 | 
				
			||||||
 | 
						$(builddir)/mgcp_test >$(srcdir)/mgcp_test.ok
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 97\r\n" \
 | 
						"m=audio 16002 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX3A_RET \
 | 
					#define MDCX3A_RET \
 | 
				
			||||||
	"200 18983215 OK\r\n" \
 | 
						"200 18983215 OK\r\n" \
 | 
				
			||||||
@@ -115,7 +115,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 97\r\n" \
 | 
						"m=audio 16002 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX3_FMTP_RET \
 | 
					#define MDCX3_FMTP_RET \
 | 
				
			||||||
	"200 18983215 OK\r\n" \
 | 
						"200 18983215 OK\r\n" \
 | 
				
			||||||
@@ -127,41 +127,49 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16006 RTP/AVP 97\r\n" \
 | 
						"m=audio 16006 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=fmtp:126 0/1/2\r\n" \
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_ADDR0000 \
 | 
					#define MDCX4_ADDR0000 \
 | 
				
			||||||
	"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\r\n" \
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_ADDR0000_RET \
 | 
					#define MDCX4_ADDR0000_RET \
 | 
				
			||||||
	"527 18983216 FAIL\r\n"
 | 
						"200 18983216 OK\r\n" \
 | 
				
			||||||
 | 
						"\r\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"s=-\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 16002 RTP/AVP 99\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4 \
 | 
					#define MDCX4 \
 | 
				
			||||||
	"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RET(Ident) \
 | 
					#define MDCX4_RET(Ident) \
 | 
				
			||||||
	"200 " Ident " OK\r\n" \
 | 
						"200 " Ident " OK\r\n" \
 | 
				
			||||||
@@ -173,7 +181,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 99\r\n" \
 | 
						"m=audio 16002 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RO_RET(Ident) \
 | 
					#define MDCX4_RO_RET(Ident) \
 | 
				
			||||||
	"200 " Ident " OK\r\n" \
 | 
						"200 " Ident " OK\r\n" \
 | 
				
			||||||
@@ -185,87 +193,87 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 112\r\n" \
 | 
						"m=audio 16002 RTP/AVP 112\r\n" \
 | 
				
			||||||
	"a=rtpmap:112 AMR\r\n" \
 | 
						"a=rtpmap:112 AMR\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT1 \
 | 
					#define MDCX4_PT1 \
 | 
				
			||||||
	"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: SENDRECV\r" \
 | 
						"M: SENDRECV\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20-40, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20-40, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT2 \
 | 
					#define MDCX4_PT2 \
 | 
				
			||||||
	"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20-20, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20-20, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT3 \
 | 
					#define MDCX4_PT3 \
 | 
				
			||||||
	"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: a:AMR, nt:IN\r\n" \
 | 
						"L: a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Test different upper/lower case in options */
 | 
					/* Test different upper/lower case in options */
 | 
				
			||||||
#define MDCX4_PT4 \
 | 
					#define MDCX4_PT4 \
 | 
				
			||||||
	"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"m: sendrecv\r" \
 | 
						"m: sendrecv\r\n" \
 | 
				
			||||||
	"c: 2\r\n" \
 | 
						"c: 2\r\n" \
 | 
				
			||||||
	"i: %s\r\n" \
 | 
						"i: %s\r\n" \
 | 
				
			||||||
	"l: A:amr, NT:IN\r\n" \
 | 
						"l: A:amr, NT:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_SO \
 | 
					#define MDCX4_SO \
 | 
				
			||||||
	"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendonly\r" \
 | 
						"M: sendonly\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r\n" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 5.6.7.8\r\n" \
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 4441 RTP/AVP 99\r\n" \
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RO \
 | 
					#define MDCX4_RO \
 | 
				
			||||||
	"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: recvonly\r" \
 | 
						"M: recvonly\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20, a:AMR, nt:IN\r\n"
 | 
						"L: p:20, a:AMR, nt:IN\r\n"
 | 
				
			||||||
@@ -298,7 +306,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"c=IN IP4 123.12.12.123\r\n" \
 | 
						"c=IN IP4 123.12.12.123\r\n" \
 | 
				
			||||||
	"m=audio 5904 RTP/AVP 97\r\n" \
 | 
						"m=audio 5904 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_RET \
 | 
					#define CRCX_RET \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
@@ -311,7 +319,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 97\r\n" \
 | 
						"m=audio 16002 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_RET_NO_RTPMAP \
 | 
					#define CRCX_RET_NO_RTPMAP \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
@@ -323,7 +331,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"c=IN IP4 0.0.0.0\r\n" \
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16002 RTP/AVP 97\r\n" \
 | 
						"m=audio 16002 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_FMTP_RET \
 | 
					#define CRCX_FMTP_RET \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
@@ -336,18 +344,17 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16006 RTP/AVP 97\r\n" \
 | 
						"m=audio 16006 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=fmtp:126 0/1/2\r\n" \
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_ZYN \
 | 
					#define CRCX_ZYN \
 | 
				
			||||||
	"CRCX 2 1@mgw MGCP 1.0\r" \
 | 
						"CRCX 2 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: recvonly\r" \
 | 
						"M: recvonly\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"\n" \
 | 
						"\r\n" \
 | 
				
			||||||
	"v=0\r" \
 | 
						"v=0\r\n" \
 | 
				
			||||||
	"c=IN IP4 123.12.12.123\r" \
 | 
						"c=IN IP4 123.12.12.123\r\n" \
 | 
				
			||||||
	"m=audio 5904 RTP/AVP 97\r" \
 | 
						"m=audio 5904 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r"
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_ZYN_RET \
 | 
					#define CRCX_ZYN_RET \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
@@ -373,7 +380,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"c=IN IP4 123.12.12.123\r\n" \
 | 
						"c=IN IP4 123.12.12.123\r\n" \
 | 
				
			||||||
	"m=audio 5904 RTP/AVP 97\r\n" \
 | 
						"m=audio 5904 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_X_OSMO_IGN_RET \
 | 
					#define CRCX_X_OSMO_IGN_RET \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
@@ -386,7 +393,95 @@ static void test_strline(void)
 | 
				
			|||||||
	"t=0 0\r\n" \
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
	"m=audio 16010 RTP/AVP 97\r\n" \
 | 
						"m=audio 16010 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_PORT_0 \
 | 
				
			||||||
 | 
						"CRCX 3 1@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 0 RTP/AVP 97\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_RET \
 | 
				
			||||||
 | 
						"200 3 OK\r\n" \
 | 
				
			||||||
 | 
						"I: %s\r\n" \
 | 
				
			||||||
 | 
						"\r\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"s=-\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 16014 RTP/AVP 97\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_IUFP \
 | 
				
			||||||
 | 
						"CRCX 4 1@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 0 RTP/AVP 96\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_IUFP_RET \
 | 
				
			||||||
 | 
						"200 4 OK\r\n" \
 | 
				
			||||||
 | 
						"I: %s\r\n" \
 | 
				
			||||||
 | 
						"\r\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"s=-\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 16016 RTP/AVP 96\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Do a CRCX in m=sendrecv */
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_IUFP_SENDRECV \
 | 
				
			||||||
 | 
						"CRCX 4 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
 | 
						"M: sendrecv\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 0 RTP/AVP 96\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Do a CRCX using sendrecv mode in the SDP part */
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_IUFP_SENDRECV2 \
 | 
				
			||||||
 | 
						"CRCX 4 1@mgw MGCP 1.0\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" \
 | 
				
			||||||
 | 
						"a=sendrecv\r\n" \
 | 
				
			||||||
 | 
						"m=audio 0 RTP/AVP 96\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Do a CRCX entirely omitting a mode, i.e. implcit sendrecv */
 | 
				
			||||||
 | 
					#define CRCX_PORT_0_IUFP_SENDRECV3 \
 | 
				
			||||||
 | 
						"CRCX 4 1@mgw MGCP 1.0\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 0 RTP/AVP 96\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DLCX \
 | 
					#define DLCX \
 | 
				
			||||||
	"DLCX 7 1@mgw MGCP 1.0\r\n" \
 | 
						"DLCX 7 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -443,7 +538,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"m=audio 5904 RTP/AVP 18 97\r\n" \
 | 
						"m=audio 5904 RTP/AVP 18 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:18 G729/8000\r\n" \
 | 
						"a=rtpmap:18 G729/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_MULT_2 \
 | 
					#define CRCX_MULT_2 \
 | 
				
			||||||
	"CRCX 2 2@mgw MGCP 1.0\r\n" \
 | 
						"CRCX 2 2@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -458,7 +553,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=rtpmap:18 G729/8000\r\n" \
 | 
						"a=rtpmap:18 G729/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:101 FOO/8000\r\n" \
 | 
						"a=rtpmap:101 FOO/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_MULT_3 \
 | 
					#define CRCX_MULT_3 \
 | 
				
			||||||
	"CRCX 2 3@mgw MGCP 1.0\r\n" \
 | 
						"CRCX 2 3@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -473,7 +568,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=rtpmap:18 G729/8000\r\n" \
 | 
						"a=rtpmap:18 G729/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:101 FOO/8000\r\n" \
 | 
						"a=rtpmap:101 FOO/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_MULT_4 \
 | 
					#define CRCX_MULT_4 \
 | 
				
			||||||
	"CRCX 2 4@mgw MGCP 1.0\r\n" \
 | 
						"CRCX 2 4@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -488,7 +583,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=rtpmap:18 G729/8000\r\n" \
 | 
						"a=rtpmap:18 G729/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=rtpmap:101 FOO/8000\r\n" \
 | 
						"a=rtpmap:101 FOO/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_MULT_GSM_EXACT \
 | 
					#define CRCX_MULT_GSM_EXACT \
 | 
				
			||||||
	"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
 | 
						"CRCX 259260421 5@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -577,7 +672,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"c=IN IP4 123.12.12.123\r\n" \
 | 
						"c=IN IP4 123.12.12.123\r\n" \
 | 
				
			||||||
	"m=audio 5904 RTP/AVP 97\r\n" \
 | 
						"m=audio 5904 RTP/AVP 97\r\n" \
 | 
				
			||||||
	"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
						"a=rtpmap:97 GSM-EFR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_NULL_RET "502 2 FAIL\r\n"
 | 
					#define CRCX_NULL_RET "502 2 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -586,7 +681,6 @@ struct mgcp_test {
 | 
				
			|||||||
	const char *req;
 | 
						const char *req;
 | 
				
			||||||
	const char *exp_resp;
 | 
						const char *exp_resp;
 | 
				
			||||||
	int ptype;
 | 
						int ptype;
 | 
				
			||||||
	const char *extra_fmtp;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct mgcp_test tests[] = {
 | 
					static const struct mgcp_test tests[] = {
 | 
				
			||||||
@@ -614,10 +708,9 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"RQNT1", RQNT, RQNT1_RET},
 | 
						{"RQNT1", RQNT, RQNT1_RET},
 | 
				
			||||||
	{"RQNT2", RQNT2, RQNT2_RET},
 | 
						{"RQNT2", RQNT2, RQNT2_RET},
 | 
				
			||||||
	{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
						{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
				
			||||||
	{"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
 | 
						{"CRCX", CRCX, CRCX_FMTP_RET, 97},
 | 
				
			||||||
	{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
 | 
						{"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
 | 
				
			||||||
	 "a=fmtp:126 0/1/2"},
 | 
						{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
				
			||||||
	{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
 | 
					 | 
				
			||||||
	{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
 | 
						{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
 | 
				
			||||||
	{"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},
 | 
				
			||||||
@@ -627,6 +720,11 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
 | 
						{"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
 | 
				
			||||||
	{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
 | 
						{"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
 | 
				
			||||||
	{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
 | 
						{"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
 | 
				
			||||||
 | 
						{"CRCX_PORT_0", CRCX_PORT_0, CRCX_PORT_0_RET, 97},
 | 
				
			||||||
 | 
						{"CRCX_PORT_0_IUFP", CRCX_PORT_0_IUFP, CRCX_PORT_0_IUFP_RET, 96},
 | 
				
			||||||
 | 
						{"CRCX_PORT_0_IUFP_SENDRECV", CRCX_PORT_0_IUFP_SENDRECV, CRCX_PORT_0_IUFP_RET, 96},
 | 
				
			||||||
 | 
						{"CRCX_PORT_0_IUFP_SENDRECV2", CRCX_PORT_0_IUFP_SENDRECV2, CRCX_PORT_0_IUFP_RET, 96},
 | 
				
			||||||
 | 
						{"CRCX_PORT_0_IUFP_SENDRECV3", CRCX_PORT_0_IUFP_SENDRECV3, CRCX_PORT_0_IUFP_RET, 96},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct mgcp_test retransmit[] = {
 | 
					static const struct mgcp_test retransmit[] = {
 | 
				
			||||||
@@ -657,12 +755,13 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int dummy_packets = 0;
 | 
					static int dummy_packets = 0;
 | 
				
			||||||
/* override and forward */
 | 
					/* override and forward */
 | 
				
			||||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 | 
					int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
 | 
				
			||||||
	       const struct sockaddr *dest_addr, socklen_t addrlen)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t dest_host =
 | 
						uint32_t dest_host =
 | 
				
			||||||
	    htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
 | 
						    htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
 | 
				
			||||||
	int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
 | 
						int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
 | 
				
			||||||
 | 
						const uint8_t *buf = msgb_data(msg);
 | 
				
			||||||
 | 
						size_t len = msgb_length(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len == sizeof(rtp_dummy_payload)
 | 
						if (len == sizeof(rtp_dummy_payload)
 | 
				
			||||||
	    && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
 | 
						    && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
 | 
				
			||||||
@@ -676,6 +775,8 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 | 
				
			|||||||
	OSMO_ASSERT(dest_host);
 | 
						OSMO_ASSERT(dest_host);
 | 
				
			||||||
	OSMO_ASSERT(dest_port);
 | 
						OSMO_ASSERT(dest_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return len;
 | 
						return len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -831,9 +932,6 @@ static void test_messages(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		dummy_packets = 0;
 | 
							dummy_packets = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
 | 
					 | 
				
			||||||
					   t->extra_fmtp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		inp = create_msg(t->req, last_conn_id);
 | 
							inp = create_msg(t->req, last_conn_id);
 | 
				
			||||||
		msg = mgcp_handle_message(cfg, inp);
 | 
							msg = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
		msgb_free(inp);
 | 
							msgb_free(inp);
 | 
				
			||||||
@@ -867,7 +965,7 @@ static void test_messages(void)
 | 
				
			|||||||
			endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
								endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
			OSMO_ASSERT(endp);
 | 
								OSMO_ASSERT(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			conn = mgcp_conn_get_rtp(endp, "1");
 | 
								conn = mgcp_endp_get_conn_rtp(endp, "1");
 | 
				
			||||||
			if (conn) {
 | 
								if (conn) {
 | 
				
			||||||
				OSMO_ASSERT(conn);
 | 
									OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -925,14 +1023,14 @@ static void test_messages(void)
 | 
				
			|||||||
			fprintf(stderr, "endpoint:%s: "
 | 
								fprintf(stderr, "endpoint:%s: "
 | 
				
			||||||
				"payload type %d (expected %d)\n",
 | 
									"payload type %d (expected %d)\n",
 | 
				
			||||||
				last_endpoint,
 | 
									last_endpoint,
 | 
				
			||||||
				conn->end.codec->payload_type, t->ptype);
 | 
									conn->end.cset.codec->payload_type, t->ptype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (t->ptype != PTYPE_IGNORE)
 | 
								if (t->ptype != PTYPE_IGNORE)
 | 
				
			||||||
				OSMO_ASSERT(conn->end.codec->payload_type ==
 | 
									OSMO_ASSERT(conn->end.cset.codec->payload_type ==
 | 
				
			||||||
					    t->ptype);
 | 
										    t->ptype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Reset them again for next test */
 | 
								/* Reset them again for next test */
 | 
				
			||||||
			conn->end.codec->payload_type = PTYPE_NONE;
 | 
								conn->end.cset.codec->payload_type = PTYPE_NONE;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1110,7 +1208,9 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
		_conn =
 | 
							_conn =
 | 
				
			||||||
		    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
							    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
				    "test-connection");
 | 
									    "test-connection");
 | 
				
			||||||
		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
							OSMO_ASSERT(_conn);
 | 
				
			||||||
 | 
							conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
 | 
				
			||||||
 | 
							OSMO_ASSERT(conn);
 | 
				
			||||||
		state = &conn->state;
 | 
							state = &conn->state;
 | 
				
			||||||
		packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
							packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1130,7 +1230,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
			     pl_test_dat[i].expected);
 | 
								     pl_test_dat[i].expected);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgcp_conn_free_all(&endp);
 | 
							mgcp_endp_free_conn_all(&endp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(trunk);
 | 
						talloc_free(trunk);
 | 
				
			||||||
@@ -1361,13 +1461,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
						_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
				"test-connection");
 | 
									"test-connection");
 | 
				
			||||||
	OSMO_ASSERT(_conn);
 | 
						OSMO_ASSERT(_conn);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
						conn = mgcp_endp_get_conn_rtp(&endp, _conn->id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp = &conn->end;
 | 
						rtp = &conn->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 | 
						OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 | 
				
			||||||
	rtp->codec = &rtp->codecs[0];
 | 
						rtp->cset.codec = &rtp->cset.codecs[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
				
			||||||
		struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
							struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
				
			||||||
@@ -1379,7 +1479,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
		OSMO_ASSERT(info->len >= 0);
 | 
							OSMO_ASSERT(info->len >= 0);
 | 
				
			||||||
		msg->l3h = msgb_put(msg, info->len);
 | 
							msg->l3h = msgb_put(msg, info->len);
 | 
				
			||||||
		memcpy((char*)msgb_l3(msg), info->data, info->len);
 | 
							memcpy((char*)msgb_l3(msg), info->data, info->len);
 | 
				
			||||||
		mgcp_rtp_end_config(&endp, 1, rtp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
 | 
							mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1413,7 +1512,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	force_monotonic_time_us = -1;
 | 
						force_monotonic_time_us = -1;
 | 
				
			||||||
	mgcp_conn_free_all(&endp);
 | 
						mgcp_endp_free_conn_all(&endp);
 | 
				
			||||||
	talloc_free(trunk);
 | 
						talloc_free(trunk);
 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1448,9 +1547,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 2@mgw with three codecs, last one ignored */
 | 
						/* Allocate 2@mgw with three codecs, last one ignored */
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1464,9 +1563,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 3@mgw with no codecs, check for PT == 0 */
 | 
						/* Allocate 3@mgw with no codecs, check for PT == 0 */
 | 
				
			||||||
	/* Note: It usually makes no sense to leave the payload type list
 | 
						/* Note: It usually makes no sense to leave the payload type list
 | 
				
			||||||
@@ -1485,9 +1584,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 4@mgw with a single codec */
 | 
						/* Allocate 4@mgw with a single codec */
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1501,9 +1600,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 18);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
						/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1517,9 +1616,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inp = create_msg(MDCX_NAT_DUMMY, conn_id);
 | 
						inp = create_msg(MDCX_NAT_DUMMY, conn_id);
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1529,9 +1628,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 3);
 | 
				
			||||||
	OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
 | 
						OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
 | 
				
			||||||
	memset(&addr, 0, sizeof(addr));
 | 
						memset(&addr, 0, sizeof(addr));
 | 
				
			||||||
	inet_aton("8.8.8.8", &addr);
 | 
						inet_aton("8.8.8.8", &addr);
 | 
				
			||||||
@@ -1546,7 +1645,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	talloc_free(endp->last_response);
 | 
						talloc_free(endp->last_response);
 | 
				
			||||||
	talloc_free(endp->last_trans);
 | 
						talloc_free(endp->last_trans);
 | 
				
			||||||
	endp->last_response = endp->last_trans = NULL;
 | 
						endp->last_response = endp->last_trans = NULL;
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(!conn);
 | 
						OSMO_ASSERT(!conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1560,9 +1659,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
						OSMO_ASSERT(conn->end.cset.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(trunk);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
@@ -1589,7 +1688,7 @@ static void test_no_cycle(void)
 | 
				
			|||||||
	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
 | 
						_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
				"test-connection");
 | 
									"test-connection");
 | 
				
			||||||
	OSMO_ASSERT(_conn);
 | 
						OSMO_ASSERT(_conn);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, _conn->id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, _conn->id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 0);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 0);
 | 
				
			||||||
@@ -2095,7 +2194,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
 | 
				
			|||||||
	int payload_type_conn_dst;
 | 
						int payload_type_conn_dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
 | 
						printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
 | 
				
			||||||
	if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
 | 
						if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) {
 | 
				
			||||||
		if (expect->payload_type_map[index_conn_src] == -EINVAL
 | 
							if (expect->payload_type_map[index_conn_src] == -EINVAL
 | 
				
			||||||
		    && expect->payload_type_map[index_conn_dst] == -EINVAL)
 | 
							    && expect->payload_type_map[index_conn_dst] == -EINVAL)
 | 
				
			||||||
			printf("    codec decision failed (expected)!\n");
 | 
								printf("    codec decision failed (expected)!\n");
 | 
				
			||||||
@@ -2105,19 +2204,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		printf("    Codec decision result:\n");
 | 
							printf("    Codec decision result:\n");
 | 
				
			||||||
		if (conn[index_conn_src].end.codec) {
 | 
							if (conn[index_conn_src].end.cset.codec) {
 | 
				
			||||||
			payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
 | 
								payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type;
 | 
				
			||||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
								printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
				
			||||||
			       index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
 | 
								       index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			payload_type_conn_src = -EINVAL;
 | 
								payload_type_conn_src = -EINVAL;
 | 
				
			||||||
			printf("    conn[%u]: codec:none, pt:none\n", index_conn_src);
 | 
								printf("    conn[%u]: codec:none, pt:none\n", index_conn_src);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn[index_conn_dst].end.codec) {
 | 
							if (conn[index_conn_dst].end.cset.codec) {
 | 
				
			||||||
			payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
 | 
								payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type;
 | 
				
			||||||
			printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
								printf("    conn[%u]: codec:%s, pt:%d\n",
 | 
				
			||||||
			       index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
 | 
								       index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name,
 | 
				
			||||||
			       payload_type_conn_dst);
 | 
								       payload_type_conn_dst);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			payload_type_conn_dst = -EINVAL;
 | 
								payload_type_conn_dst = -EINVAL;
 | 
				
			||||||
@@ -2144,7 +2243,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s
 | 
				
			|||||||
static void test_mgcp_codec_decide(void)
 | 
					static void test_mgcp_codec_decide(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	bool ok = true;
 | 
						bool ok_all = true;
 | 
				
			||||||
	printf("\nTesting mgcp_codec_find_convertible()\n");
 | 
						printf("\nTesting mgcp_codec_find_convertible()\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
 | 
				
			||||||
@@ -2153,6 +2252,7 @@ static void test_mgcp_codec_decide(void)
 | 
				
			|||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
		int conn_i;
 | 
							int conn_i;
 | 
				
			||||||
		int c;
 | 
							int c;
 | 
				
			||||||
 | 
							bool ok = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("#%d: %s\n", i, t->descr);
 | 
							printf("#%d: %s\n", i, t->descr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2164,8 +2264,8 @@ static void test_mgcp_codec_decide(void)
 | 
				
			|||||||
				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_codecset_add_codec(&conn[conn_i].end.cset, codec->payload_type,
 | 
				
			||||||
						    codec->param);
 | 
												     codec->audio_name, 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 ?
 | 
				
			||||||
@@ -2193,9 +2293,12 @@ static void test_mgcp_codec_decide(void)
 | 
				
			|||||||
			printf(" ===> SUCCESS: codec decision as expected!\n");
 | 
								printf(" ===> SUCCESS: codec decision as expected!\n");
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			printf(" ===> FAIL: unexpected codec decision!\n");
 | 
								printf(" ===> FAIL: unexpected codec decision!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!ok)
 | 
				
			||||||
 | 
								ok_all = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(ok);
 | 
						OSMO_ASSERT(ok_all);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_conn_id_matching(void)
 | 
					void test_conn_id_matching(void)
 | 
				
			||||||
@@ -2228,7 +2331,7 @@ void test_conn_id_matching(void)
 | 
				
			|||||||
	for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
 | 
				
			||||||
		const char *needle = conn_id_request[i];
 | 
							const char *needle = conn_id_request[i];
 | 
				
			||||||
		printf("needle='%s' ", needle);
 | 
							printf("needle='%s' ", needle);
 | 
				
			||||||
		conn_match = mgcp_conn_get(&endp, needle);
 | 
							conn_match = mgcp_endp_get_conn(&endp, needle);
 | 
				
			||||||
		OSMO_ASSERT(conn_match);
 | 
							OSMO_ASSERT(conn_match);
 | 
				
			||||||
		printf("found '%s'\n", conn_match->id);
 | 
							printf("found '%s'\n", conn_match->id);
 | 
				
			||||||
		OSMO_ASSERT(conn_match == conn);
 | 
							OSMO_ASSERT(conn_match == conn);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -101,7 +101,8 @@ Testing MDCX4_ADDR000
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983216 1@mgw MGCP 1.0
 | 
					MDCX 18983216 1@mgw MGCP 1.0
 | 
				
			||||||
M: sendrecv
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,20 +112,21 @@ c=IN IP4 0.0.0.0
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
checking response:
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
Response matches our expectations.
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4
 | 
					Testing MDCX4
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983217 1@mgw MGCP 1.0
 | 
					MDCX 18983217 1@mgw MGCP 1.0
 | 
				
			||||||
MDCX 18983217 1@mgw MGCP 1.0
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -134,7 +136,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -148,7 +150,8 @@ Testing MDCX4_PT1
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983218 1@mgw MGCP 1.0
 | 
					MDCX 18983218 1@mgw MGCP 1.0
 | 
				
			||||||
---------8<---------
 | 
					M: SENDRECV
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20-40, a:AMR, nt:IN
 | 
					L: p:20-40, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,7 +161,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
t=0 0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -172,7 +175,8 @@ Testing MDCX4_PT2
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983219 1@mgw MGCP 1.0
 | 
					MDCX 18983219 1@mgw MGCP 1.0
 | 
				
			||||||
creating message from statically defined input:
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20-20, a:AMR, nt:IN
 | 
					L: p:20-20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -182,7 +186,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
c=IN IP4 5.6.7.8
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -196,7 +200,8 @@ Testing MDCX4_PT3
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983220 1@mgw MGCP 1.0
 | 
					MDCX 18983220 1@mgw MGCP 1.0
 | 
				
			||||||
Testing MDCX4_PT3
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: a:AMR, nt:IN
 | 
					L: a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,7 +211,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
o=- %s 23 IN IP4 5.6.7.8
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -220,7 +225,8 @@ Testing MDCX4_PT4
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983221 1@mgw MGCP 1.0
 | 
					MDCX 18983221 1@mgw MGCP 1.0
 | 
				
			||||||
================================================
 | 
					m: sendrecv
 | 
				
			||||||
 | 
					c: 2
 | 
				
			||||||
i: %s
 | 
					i: %s
 | 
				
			||||||
l: A:amr, NT:IN
 | 
					l: A:amr, NT:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,7 +236,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
v=0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -244,7 +250,8 @@ Testing MDCX4_SO
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983222 1@mgw MGCP 1.0
 | 
					MDCX 18983222 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: sendonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -254,7 +261,7 @@ c=IN IP4 5.6.7.8
 | 
				
			|||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -267,7 +274,8 @@ Testing MDCX4_RO
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983223 1@mgw MGCP 1.0
 | 
					MDCX 18983223 1@mgw MGCP 1.0
 | 
				
			||||||
(response contains a connection id)
 | 
					M: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -296,9 +304,15 @@ Response matches our expectations.
 | 
				
			|||||||
Testing CRCX_ZYN
 | 
					Testing CRCX_ZYN
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
using message as statically defined for comparison
 | 
					CRCX 2 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(response does not contain a connection id)
 | 
					 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
@@ -414,7 +428,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
================================================
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -479,7 +493,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing CRCX
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -550,7 +564,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
================================================
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -599,6 +613,110 @@ using message as statically defined for comparison
 | 
				
			|||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response does not contain a connection id)
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 3 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 97
 | 
				
			||||||
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV2
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					a=sendrecv
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV3
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing CRCX
 | 
					Testing CRCX
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -612,7 +730,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
================================================
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -630,7 +748,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Response matches our expectations.
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -742,7 +860,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Response matches our expectations.
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1196,7 +1314,7 @@ c=IN IP4 123.12.12.123
 | 
				
			|||||||
m=audio 5904 RTP/AVP 18 97
 | 
					m=audio 5904 RTP/AVP 18 97
 | 
				
			||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
creating message from statically defined input:
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1213,7 +1331,7 @@ m=audio 5904 RTP/AVP 18 97 101
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
---------8<---------
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1230,7 +1348,7 @@ m=audio 5904 RTP/AVP
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
---------8<---------
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1247,7 +1365,7 @@ m=audio 5904 RTP/AVP 18
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
---------8<---------
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1329,7 +1447,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing no sequence flow on initial packet
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,9 +107,6 @@ void test_response_cb(struct mgcp_response *response, void *priv)
 | 
				
			|||||||
	printf("  audio_port = %u\n", response->audio_port);
 | 
						printf("  audio_port = %u\n", response->audio_port);
 | 
				
			||||||
	printf("  audio_ip = %s\n", response->audio_ip);
 | 
						printf("  audio_ip = %s\n", response->audio_ip);
 | 
				
			||||||
	printf("  ptime = %u\n", response->ptime);
 | 
						printf("  ptime = %u\n", response->ptime);
 | 
				
			||||||
	printf("  codecs_len = %u\n", response->codecs_len);
 | 
					 | 
				
			||||||
	for(i=0;i<response->codecs_len;i++)
 | 
					 | 
				
			||||||
		printf("  codecs[%u] = %u\n", i, response->codecs[i]);
 | 
					 | 
				
			||||||
	printf("  ptmap_len = %u\n", response->ptmap_len);
 | 
						printf("  ptmap_len = %u\n", response->ptmap_len);
 | 
				
			||||||
	for(i=0;i<response->ptmap_len;i++) {
 | 
						for(i=0;i<response->ptmap_len;i++) {
 | 
				
			||||||
		printf("  ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
 | 
							printf("  ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
 | 
				
			||||||
@@ -149,12 +146,11 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
		.conn_id = "11",
 | 
							.conn_id = "11",
 | 
				
			||||||
		.conn_mode = MGCP_CONN_RECV_SEND,
 | 
							.conn_mode = MGCP_CONN_RECV_SEND,
 | 
				
			||||||
		.ptime = 20,
 | 
							.ptime = 20,
 | 
				
			||||||
		.codecs[0] = CODEC_GSM_8000_1,
 | 
							.ptmap = {
 | 
				
			||||||
		.codecs[1] = CODEC_AMR_8000_1,
 | 
								{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
 | 
				
			||||||
		.codecs[2] = CODEC_GSMEFR_8000_1,
 | 
								{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
 | 
				
			||||||
		.codecs_len = 1,
 | 
								{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
 | 
				
			||||||
		.ptmap[0].codec = CODEC_GSMEFR_8000_1,
 | 
							},
 | 
				
			||||||
		.ptmap[0].pt = 96,
 | 
					 | 
				
			||||||
		.ptmap_len = 1,
 | 
							.ptmap_len = 1,
 | 
				
			||||||
		.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
							.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
				
			||||||
		.x_osmo_osmux_cid = -1, /* wildcard */
 | 
							.x_osmo_osmux_cid = -1, /* wildcard */
 | 
				
			||||||
@@ -179,9 +175,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	mgcp_msg.presence =
 | 
						mgcp_msg.presence =
 | 
				
			||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
				
			||||||
	mgcp_msg.codecs_len = 2;
 | 
						mgcp_msg.ptmap_len = 2;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated CRCX message (three codecs, one with custom pt):\n");
 | 
						printf("Generated CRCX message (three codecs, one with custom pt):\n");
 | 
				
			||||||
@@ -189,9 +185,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	mgcp_msg.presence =
 | 
						mgcp_msg.presence =
 | 
				
			||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
				
			||||||
	mgcp_msg.codecs_len = 3;
 | 
						mgcp_msg.ptmap_len = 3;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated MDCX message:\n");
 | 
						printf("Generated MDCX message:\n");
 | 
				
			||||||
@@ -209,9 +205,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
	mgcp_msg.codecs_len = 2;
 | 
						mgcp_msg.ptmap_len = 2;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated MDCX message (three codecs, one with custom pt):\n");
 | 
						printf("Generated MDCX message (three codecs, one with custom pt):\n");
 | 
				
			||||||
@@ -220,9 +216,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
	mgcp_msg.codecs_len = 3;
 | 
						mgcp_msg.ptmap_len = 3;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated DLCX message:\n");
 | 
						printf("Generated DLCX message:\n");
 | 
				
			||||||
@@ -330,8 +326,10 @@ void test_mgcp_client_cancel(void)
 | 
				
			|||||||
		.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
 | 
							.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
 | 
				
			||||||
			     | MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
 | 
								     | MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
 | 
				
			||||||
		.ptime = 20,
 | 
							.ptime = 20,
 | 
				
			||||||
		.codecs[0] = CODEC_AMR_8000_1,
 | 
							.ptmap = {
 | 
				
			||||||
		.codecs_len = 1
 | 
								{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.ptmap_len = 1
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n%s():\n", __func__);
 | 
						printf("\n%s():\n", __func__);
 | 
				
			||||||
@@ -531,7 +529,7 @@ void test_sdp_section_start(void)
 | 
				
			|||||||
	OSMO_ASSERT(!failures);
 | 
						OSMO_ASSERT(!failures);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_map_pt_to_codec(void)
 | 
					static void test_map_str_to_codec(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Full form */
 | 
						/* Full form */
 | 
				
			||||||
	OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
 | 
						OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
 | 
				
			||||||
@@ -675,6 +673,214 @@ void test_mgcp_client_e1_epname(void)
 | 
				
			|||||||
	OSMO_ASSERT(epname == NULL);
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct parse_response_test {
 | 
				
			||||||
 | 
						const char *body;
 | 
				
			||||||
 | 
						int expect_rc;
 | 
				
			||||||
 | 
						struct mgcp_response expect_params;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct parse_response_test parse_response_tests[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 112 3\r\n" /* <-- implicit: 3 = GSM-FR */
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 112 3\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:3 GSM/8000\r\n" /* 3 == GSM-FR implicitly, is an explicit entry a problem? */
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 }, /* no, not a problem */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 3\r\n" /* <-- 112 is missing here. Will it still appear? */
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 }, /* <-- yes, it was added to the end. */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* test MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\n" /* <-- 10 codecs max */
 | 
				
			||||||
 | 
								"a=rtpmap:101 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:102 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:103 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:104 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:105 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:106 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:107 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:108 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:109 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:110 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 101 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 102 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 103 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 104 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 105 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 106 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 107 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 108 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 109 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 110 },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 10,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* test MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\n" /* <-- 11 > MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
								"a=rtpmap:101 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:102 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:103 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:104 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:105 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:106 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:107 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:108 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:109 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:110 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -EINVAL,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_parse_response(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int failures = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(parse_response_tests); i++) {
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
							struct parse_response_test *t = &parse_response_tests[i];
 | 
				
			||||||
 | 
							struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
 | 
				
			||||||
 | 
							int p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r->body = talloc_strdup(r, t->body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//printf("\n%s() test [%d]:\n", __func__, i);
 | 
				
			||||||
 | 
							fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
 | 
				
			||||||
 | 
							fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = mgcp_response_parse_params(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fprintf(stderr, "got rc=%d\n", rc);
 | 
				
			||||||
 | 
							if (rc != t->expect_rc) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (rc) {
 | 
				
			||||||
 | 
								talloc_free(r);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
 | 
				
			||||||
 | 
							if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fprintf(stderr, "got audio_port=%u\n", r->audio_port);
 | 
				
			||||||
 | 
							if (r->audio_port != t->expect_params.audio_port) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (p = 0; p < r->ptmap_len; p++) {
 | 
				
			||||||
 | 
								struct ptmap *got = &r->ptmap[p];
 | 
				
			||||||
 | 
								struct ptmap *expect = NULL;
 | 
				
			||||||
 | 
								fprintf(stderr, "  %d %s\n", got->pt, osmo_mgcpc_codec_name(got->codec));
 | 
				
			||||||
 | 
								if (p >= t->expect_params.ptmap_len) {
 | 
				
			||||||
 | 
									fprintf(stderr, "    - ERROR: too many codec entries\n");
 | 
				
			||||||
 | 
									failures++;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								expect = &t->expect_params.ptmap[p];
 | 
				
			||||||
 | 
								if (ptmap_cmp(got, expect)) {
 | 
				
			||||||
 | 
									fprintf(stderr, "    - ERROR: expected: %d %s\n",
 | 
				
			||||||
 | 
										expect->pt, osmo_mgcpc_codec_name(expect->codec));
 | 
				
			||||||
 | 
									failures++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							talloc_free(r);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(!failures);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat log_categories[] = {
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -703,9 +909,11 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_mgcp_client_cancel();
 | 
						test_mgcp_client_cancel();
 | 
				
			||||||
	test_sdp_section_start();
 | 
						test_sdp_section_start();
 | 
				
			||||||
	test_map_codec_to_pt_and_map_pt_to_codec();
 | 
						test_map_codec_to_pt_and_map_pt_to_codec();
 | 
				
			||||||
	test_map_pt_to_codec();
 | 
						test_map_str_to_codec();
 | 
				
			||||||
	test_mgcp_client_e1_epname();
 | 
						test_mgcp_client_e1_epname();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_parse_response();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Done\n");
 | 
						printf("Done\n");
 | 
				
			||||||
	fprintf(stderr, "Done\n");
 | 
						fprintf(stderr, "Done\n");
 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -137,4 +137,51 @@ DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw),
 | 
				
			|||||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
 | 
					DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
 | 
				
			||||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
 | 
					DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
 | 
				
			||||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
 | 
					DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [0]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [1]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:3 GSM/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [2]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					DLMGCP error in MGCP message: 'a=rtpmap:112' has no matching entry in 'm=audio ... 112'
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [3]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR/8"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  101 AMR/8000/1
 | 
				
			||||||
 | 
					  102 AMR/8000/1
 | 
				
			||||||
 | 
					  103 AMR/8000/1
 | 
				
			||||||
 | 
					  104 AMR/8000/1
 | 
				
			||||||
 | 
					  105 AMR/8000/1
 | 
				
			||||||
 | 
					  106 AMR/8000/1
 | 
				
			||||||
 | 
					  107 AMR/8000/1
 | 
				
			||||||
 | 
					  108 AMR/8000/1
 | 
				
			||||||
 | 
					  109 AMR/8000/1
 | 
				
			||||||
 | 
					  110 AMR/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [4]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR"
 | 
				
			||||||
 | 
					DLMGCP SDP: can parse only up to 10 payload type numbers
 | 
				
			||||||
 | 
					DLMGCP Failed to parse SDP parameter payload types (RTP/AVP)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
Done
 | 
					Done
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user