mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			120 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cfef36837e | ||
| 
						 | 
					c946605208 | ||
| 
						 | 
					a02faff1ac | ||
| 
						 | 
					ce055d5ac4 | ||
| 
						 | 
					452f2ba5bd | ||
| 
						 | 
					0b6faa4521 | ||
| 
						 | 
					1c69fb0f14 | ||
| 
						 | 
					069dd16b67 | ||
| 
						 | 
					e144275757 | ||
| 
						 | 
					e0058b7207 | ||
| 
						 | 
					bb3ccdea1a | ||
| 
						 | 
					2799ff9bb9 | ||
| 
						 | 
					fed5feafd3 | ||
| 
						 | 
					1de5ed6f97 | ||
| 
						 | 
					80751d850b | ||
| 
						 | 
					2c40164ff0 | ||
| 
						 | 
					e308202285 | ||
| 
						 | 
					b4a067c9fb | ||
| 
						 | 
					8029b12146 | ||
| 
						 | 
					ebb05c1f90 | ||
| 
						 | 
					bc3f3b40fe | ||
| 
						 | 
					fae09f4562 | ||
| 
						 | 
					7c0fe31697 | ||
| 
						 | 
					98aef217c6 | ||
| 
						 | 
					e03e34f8bb | ||
| 
						 | 
					ee6958c9a8 | ||
| 
						 | 
					fbcf4a6f6c | ||
| 
						 | 
					58dc88bc31 | ||
| 
						 | 
					aac84edc9d | ||
| 
						 | 
					172f5acfce | ||
| 
						 | 
					fdbefde869 | ||
| 
						 | 
					25ecc91c3b | ||
| 
						 | 
					995529548b | ||
| 
						 | 
					0c04500ac5 | ||
| 
						 | 
					a0b69f1896 | ||
| 
						 | 
					fbf78d13f1 | ||
| 
						 | 
					df9192efee | ||
| 
						 | 
					70a658a2ba | ||
| 
						 | 
					2764bdb1aa | ||
| 
						 | 
					55fdfc223e | ||
| 
						 | 
					8f33303660 | ||
| 
						 | 
					a94c56e4c6 | ||
| 
						 | 
					2ebcf5c34a | ||
| 
						 | 
					f936e10f07 | ||
| 
						 | 
					e303fa9ff3 | ||
| 
						 | 
					958f5e74cc | ||
| 
						 | 
					1e8d5fa44b | ||
| 
						 | 
					374ad788d8 | ||
| 
						 | 
					da07b90f0f | ||
| 
						 | 
					fa495d669f | ||
| 
						 | 
					439c86fc58 | ||
| 
						 | 
					74e83d3d82 | ||
| 
						 | 
					d55be05af1 | ||
| 
						 | 
					8f91a7f450 | ||
| 
						 | 
					da3a5759e1 | ||
| 
						 | 
					29e671f257 | ||
| 
						 | 
					d6a7e17911 | ||
| 
						 | 
					3f4a4cb49c | ||
| 
						 | 
					3d2b76fd95 | ||
| 
						 | 
					276a414aa3 | ||
| 
						 | 
					c534ad17dc | ||
| 
						 | 
					3f2c15f275 | ||
| 
						 | 
					38533ba9b3 | ||
| 
						 | 
					39889e4389 | ||
| 
						 | 
					c824fe4eb0 | ||
| 
						 | 
					124a3e0b34 | ||
| 
						 | 
					96c6e06681 | ||
| 
						 | 
					ce18705875 | ||
| 
						 | 
					41ab87f67c | ||
| 
						 | 
					a8739fc7be | ||
| 
						 | 
					21dfeff8aa | ||
| 
						 | 
					f486e741a4 | ||
| 
						 | 
					268568593e | ||
| 
						 | 
					41d59205c0 | ||
| 
						 | 
					036612b035 | ||
| 
						 | 
					6bad138c96 | ||
| 
						 | 
					8dc3597085 | ||
| 
						 | 
					d70eef6421 | ||
| 
						 | 
					33d97f721d | ||
| 
						 | 
					d57310731f | ||
| 
						 | 
					a8c684b51f | ||
| 
						 | 
					03fcc91aad | ||
| 
						 | 
					9de30e7cc4 | ||
| 
						 | 
					d64c041cdb | ||
| 
						 | 
					d02716d6c2 | ||
| 
						 | 
					a065e632c0 | ||
| 
						 | 
					bd060c3c99 | ||
| 
						 | 
					97cae477fb | ||
| 
						 | 
					02c880a7dd | ||
| 
						 | 
					ba09687768 | ||
| 
						 | 
					a4b677c45a | ||
| 
						 | 
					6b7afe8f57 | ||
| 
						 | 
					4131a65c4d | ||
| 
						 | 
					6a5e5ac2d4 | ||
| 
						 | 
					b066bd0c86 | ||
| 
						 | 
					d6769ea207 | ||
| 
						 | 
					ca280a1a84 | ||
| 
						 | 
					a24dcc61d7 | ||
| 
						 | 
					62d9df684f | ||
| 
						 | 
					8358c4ba07 | ||
| 
						 | 
					4c77e9b748 | ||
| 
						 | 
					33347a4f5d | ||
| 
						 | 
					7d86d4c523 | ||
| 
						 | 
					eb984bd630 | ||
| 
						 | 
					b3d14eb552 | ||
| 
						 | 
					907744e2fc | ||
| 
						 | 
					776846a0b9 | ||
| 
						 | 
					59e7cf4437 | ||
| 
						 | 
					b2064423fe | ||
| 
						 | 
					97a9312be8 | ||
| 
						 | 
					427cede4ba | ||
| 
						 | 
					7371663aeb | ||
| 
						 | 
					fe53edd776 | ||
| 
						 | 
					4f6a7ad5f8 | ||
| 
						 | 
					55a9229922 | ||
| 
						 | 
					7802ccc8d6 | ||
| 
						 | 
					3ff5151661 | ||
| 
						 | 
					5936a9c23e | ||
| 
						 | 
					9ffaba7c1b | ||
| 
						 | 
					535ede2598 | 
							
								
								
									
										118
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					# SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# clang-format configuration file. Intended for clang-format >= 4.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# For more information, see:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   Documentation/process/clang-format.rst
 | 
				
			||||||
 | 
					#   https://clang.llvm.org/docs/ClangFormat.html
 | 
				
			||||||
 | 
					#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					AccessModifierOffset: -4
 | 
				
			||||||
 | 
					AlignAfterOpenBracket: Align
 | 
				
			||||||
 | 
					AlignConsecutiveAssignments: false
 | 
				
			||||||
 | 
					AlignConsecutiveDeclarations: false
 | 
				
			||||||
 | 
					#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					AlignOperands: true
 | 
				
			||||||
 | 
					AlignTrailingComments: false
 | 
				
			||||||
 | 
					AllowAllParametersOfDeclarationOnNextLine: false
 | 
				
			||||||
 | 
					AllowShortBlocksOnASingleLine: false
 | 
				
			||||||
 | 
					AllowShortCaseLabelsOnASingleLine: false
 | 
				
			||||||
 | 
					AllowShortFunctionsOnASingleLine: None
 | 
				
			||||||
 | 
					AllowShortIfStatementsOnASingleLine: false
 | 
				
			||||||
 | 
					AllowShortLoopsOnASingleLine: false
 | 
				
			||||||
 | 
					AlwaysBreakAfterDefinitionReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakAfterReturnType: None
 | 
				
			||||||
 | 
					AlwaysBreakBeforeMultilineStrings: false
 | 
				
			||||||
 | 
					AlwaysBreakTemplateDeclarations: false
 | 
				
			||||||
 | 
					BinPackArguments: true
 | 
				
			||||||
 | 
					BinPackParameters: true
 | 
				
			||||||
 | 
					BraceWrapping:
 | 
				
			||||||
 | 
					  AfterClass: false
 | 
				
			||||||
 | 
					  AfterControlStatement: false
 | 
				
			||||||
 | 
					  AfterEnum: false
 | 
				
			||||||
 | 
					  AfterFunction: true
 | 
				
			||||||
 | 
					  AfterNamespace: true
 | 
				
			||||||
 | 
					  AfterObjCDeclaration: false
 | 
				
			||||||
 | 
					  AfterStruct: false
 | 
				
			||||||
 | 
					  AfterUnion: false
 | 
				
			||||||
 | 
					  #AfterExternBlock: false # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					  BeforeCatch: false
 | 
				
			||||||
 | 
					  BeforeElse: false
 | 
				
			||||||
 | 
					  IndentBraces: false
 | 
				
			||||||
 | 
					  #SplitEmptyFunction: true # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					  #SplitEmptyRecord: true # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					  #SplitEmptyNamespace: true # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					BreakBeforeBinaryOperators: None
 | 
				
			||||||
 | 
					BreakBeforeBraces: Custom
 | 
				
			||||||
 | 
					#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					BreakBeforeTernaryOperators: false
 | 
				
			||||||
 | 
					BreakConstructorInitializersBeforeComma: false
 | 
				
			||||||
 | 
					#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					BreakAfterJavaFieldAnnotations: false
 | 
				
			||||||
 | 
					BreakStringLiterals: false
 | 
				
			||||||
 | 
					ColumnLimit: 120
 | 
				
			||||||
 | 
					CommentPragmas: '^ IWYU pragma:'
 | 
				
			||||||
 | 
					#CompactNamespaces: false # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					ConstructorInitializerAllOnOneLineOrOnePerLine: false
 | 
				
			||||||
 | 
					ConstructorInitializerIndentWidth: 8
 | 
				
			||||||
 | 
					ContinuationIndentWidth: 8
 | 
				
			||||||
 | 
					Cpp11BracedListStyle: false
 | 
				
			||||||
 | 
					DerivePointerAlignment: false
 | 
				
			||||||
 | 
					DisableFormat: false
 | 
				
			||||||
 | 
					ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
 | 
					#FixNamespaceComments: false # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#IncludeBlocks: Preserve # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					IncludeCategories:
 | 
				
			||||||
 | 
					  - Regex: '.*'
 | 
				
			||||||
 | 
					    Priority: 1
 | 
				
			||||||
 | 
					IncludeIsMainRegex: '(Test)?$'
 | 
				
			||||||
 | 
					IndentCaseLabels: false
 | 
				
			||||||
 | 
					#IndentPPDirectives: None # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					IndentWidth: 8
 | 
				
			||||||
 | 
					IndentWrappedFunctionNames: false
 | 
				
			||||||
 | 
					JavaScriptQuotes: Leave
 | 
				
			||||||
 | 
					JavaScriptWrapImports: true
 | 
				
			||||||
 | 
					KeepEmptyLinesAtTheStartOfBlocks: false
 | 
				
			||||||
 | 
					MacroBlockBegin: ''
 | 
				
			||||||
 | 
					MacroBlockEnd: ''
 | 
				
			||||||
 | 
					MaxEmptyLinesToKeep: 1
 | 
				
			||||||
 | 
					NamespaceIndentation: None
 | 
				
			||||||
 | 
					#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					ObjCBlockIndentWidth: 8
 | 
				
			||||||
 | 
					ObjCSpaceAfterProperty: true
 | 
				
			||||||
 | 
					ObjCSpaceBeforeProtocolList: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Taken from git's rules
 | 
				
			||||||
 | 
					#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					PenaltyBreakBeforeFirstCallParameter: 30
 | 
				
			||||||
 | 
					PenaltyBreakComment: 10
 | 
				
			||||||
 | 
					PenaltyBreakFirstLessLess: 0
 | 
				
			||||||
 | 
					PenaltyBreakString: 10
 | 
				
			||||||
 | 
					PenaltyExcessCharacter: 100
 | 
				
			||||||
 | 
					PenaltyReturnTypeOnItsOwnLine: 60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PointerAlignment: Right
 | 
				
			||||||
 | 
					ReflowComments: false
 | 
				
			||||||
 | 
					SortIncludes: false
 | 
				
			||||||
 | 
					#SortUsingDeclarations: false # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					SpaceAfterCStyleCast: false
 | 
				
			||||||
 | 
					SpaceAfterTemplateKeyword: true
 | 
				
			||||||
 | 
					SpaceBeforeAssignmentOperators: true
 | 
				
			||||||
 | 
					#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					SpaceBeforeParens: ControlStatements
 | 
				
			||||||
 | 
					#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
 | 
				
			||||||
 | 
					SpaceInEmptyParentheses: false
 | 
				
			||||||
 | 
					SpacesBeforeTrailingComments: 1
 | 
				
			||||||
 | 
					SpacesInAngles: false
 | 
				
			||||||
 | 
					SpacesInContainerLiterals: false
 | 
				
			||||||
 | 
					SpacesInCStyleCastParentheses: false
 | 
				
			||||||
 | 
					SpacesInParentheses: false
 | 
				
			||||||
 | 
					SpacesInSquareBrackets: false
 | 
				
			||||||
 | 
					Standard: Cpp03
 | 
				
			||||||
 | 
					TabWidth: 8
 | 
				
			||||||
 | 
					UseTab: Always
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -64,3 +64,8 @@ doc/manuals/common
 | 
				
			|||||||
doc/manuals/build
 | 
					doc/manuals/build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
contrib/osmo-mgw.spec
 | 
					contrib/osmo-mgw.spec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#vs code
 | 
				
			||||||
 | 
					.cache
 | 
				
			||||||
 | 
					.vscode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
To run the configuration parsing and output (VTY) test suite, first install
 | 
					To run the configuration parsing and output (VTY) test suite, first install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  git://git.osmocom.org/python/osmo-python-tests
 | 
					  https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
and pass the following configure options here:
 | 
					and pass the following configure options here:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								configure.ac
									
									
									
									
									
								
							@@ -36,11 +36,6 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
PKG_PROG_PKG_CONFIG([0.20])
 | 
					PKG_PROG_PKG_CONFIG([0.20])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl check for AX_CHECK_COMPILE_FLAG
 | 
					 | 
				
			||||||
m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
 | 
					 | 
				
			||||||
	AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
 | 
					 | 
				
			||||||
	])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dnl checks for libraries
 | 
					dnl checks for libraries
 | 
				
			||||||
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
 | 
					AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
 | 
				
			||||||
AC_SUBST(LIBRARY_DL)
 | 
					AC_SUBST(LIBRARY_DL)
 | 
				
			||||||
@@ -49,13 +44,16 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
 | 
				
			|||||||
AC_SUBST(LIBRARY_DLSYM)
 | 
					AC_SUBST(LIBRARY_DLSYM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.3.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS="$CFLAGS -pthread"
 | 
				
			||||||
 | 
					LDFLAGS="$LDFLAGS -pthread"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -87,15 +85,6 @@ then
 | 
				
			|||||||
	CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 | 
						CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl Checks for typedefs, structures and compiler characteristics
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Coverage build taken from WebKit's configure.in
 | 
					# Coverage build taken from WebKit's configure.in
 | 
				
			||||||
AC_MSG_CHECKING([whether to enable code coverage support])
 | 
					AC_MSG_CHECKING([whether to enable code coverage support])
 | 
				
			||||||
AC_ARG_ENABLE(coverage,
 | 
					AC_ARG_ENABLE(coverage,
 | 
				
			||||||
@@ -123,7 +112,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
 | 
				
			|||||||
	AM_PATH_PYTHON
 | 
						AM_PATH_PYTHON
 | 
				
			||||||
	AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
 | 
						AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
 | 
				
			||||||
	 if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
 | 
						 if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
 | 
				
			||||||
		AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
 | 
							AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
					AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,6 @@
 | 
				
			|||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 * GNU General Public License for more details.
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU General Public License along
 | 
					 | 
				
			||||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
					 | 
				
			||||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ set -x
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
cd "$base"
 | 
					cd "$base"
 | 
				
			||||||
autoreconf --install --force
 | 
					autoreconf --install --force
 | 
				
			||||||
./configure --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
 | 
					./configure --enable-sanitize --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
 | 
				
			||||||
$MAKE $PARALLEL_MAKE
 | 
					$MAKE $PARALLEL_MAKE
 | 
				
			||||||
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
 | 
					LD_LIBRARY_PATH="$inst/lib" $MAKE check \
 | 
				
			||||||
  || cat-testlogs.sh
 | 
					  || cat-testlogs.sh
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,30 +29,30 @@ BuildRequires:  pkgconfig >= 0.20
 | 
				
			|||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
%endif
 | 
					%endif
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.1.0
 | 
					BuildRequires:  pkgconfig(libosmo-netif) >= 1.2.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.7.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.7.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmogsm) >= 1.7.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.7.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.5.0
 | 
					BuildRequires:  pkgconfig(libosmocoding) >= 1.7.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.1.0
 | 
					BuildRequires:  pkgconfig(libosmoabis) >= 1.3.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.1.0
 | 
					BuildRequires:  pkgconfig(libosmotrau) >= 1.3.0
 | 
				
			||||||
%{?systemd_requires}
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description
 | 
					%description
 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client8
 | 
					%package -n libosmo-mgcp-client9
 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          System/Libraries
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client8
 | 
					%description -n libosmo-mgcp-client9
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					Osmocom's Media Gateway Control Protocol client library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					%package -n libosmo-mgcp-client-devel
 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					Group:          Development/Libraries/C and C++
 | 
				
			||||||
Requires:       libosmo-mgcp-client8 = %{version}
 | 
					Requires:       libosmo-mgcp-client9 = %{version}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					%description -n libosmo-mgcp-client-devel
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					Osmocom's Media Gateway Control Protocol client librarary.
 | 
				
			||||||
@@ -90,8 +90,8 @@ find %{buildroot} -type f -name "*.la" -delete -print
 | 
				
			|||||||
%check
 | 
					%check
 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%post   -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
					%post   -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
				
			||||||
%postun -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
					%postun -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
%preun
 | 
					%preun
 | 
				
			||||||
@@ -119,8 +119,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
%dir %{_sysconfdir}/osmocom
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client8
 | 
					%files -n libosmo-mgcp-client9
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.6*
 | 
					%{_libdir}/libosmo-mgcp-client.so.9*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					%files -n libosmo-mgcp-client-devel
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					%{_libdir}/libosmo-mgcp-client.so
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										164
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										164
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,167 @@
 | 
				
			|||||||
 | 
					osmo-mgw (1.10.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Eric ]
 | 
				
			||||||
 | 
					  * adjust mgcp response context
 | 
				
			||||||
 | 
					  * rework message handling
 | 
				
			||||||
 | 
					  * add a lock-free bounded spsc interthread queue
 | 
				
			||||||
 | 
					  * clang-format: remove foreach macros
 | 
				
			||||||
 | 
					  * fix mgcp_conn_free_all ubsan complaints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * configuration: point out difference between trunk-nr and e1 line nr
 | 
				
			||||||
 | 
					  * mgcp_client: add new codec IUFP as VND.3GPP.IUFP
 | 
				
			||||||
 | 
					  * mgcp_codec: do not differentiate between oa and bwe when comparing codec
 | 
				
			||||||
 | 
					  * mgcp_network: do not try to convert RTCP packets
 | 
				
			||||||
 | 
					  * mgcp_network: fix typo RTPC -> RTCP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * treewide: remove FSF address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp_network.c: Set proper CRC Header for ACK Initialization
 | 
				
			||||||
 | 
					  * cosmetic: Rename variable payload=>payload_type
 | 
				
			||||||
 | 
					  * mgcp_network.c: Fix byte alignment of CRC Header for ACK Initialization
 | 
				
			||||||
 | 
					  * Define mgcp_rtp_end.output_enabled as bool
 | 
				
			||||||
 | 
					  * cosmetic: mgcp_codec.c: Fix typo in comment
 | 
				
			||||||
 | 
					  * Drop unneeded ax_check_compile_flag.m4
 | 
				
			||||||
 | 
					  * Make function amr_is_octet_aligned publicly available
 | 
				
			||||||
 | 
					  * Initial IuUP support using proper FSMs
 | 
				
			||||||
 | 
					  * IuUP: Support RFCI ID != RFCI Index
 | 
				
			||||||
 | 
					  * iuup: Fix caps in logging message
 | 
				
			||||||
 | 
					  * iuup: Check for IuUP Initialization retrans
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Alexander Couzens ]
 | 
				
			||||||
 | 
					  * doc/overview: fix wrong project page link
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
 | 
				
			||||||
 | 
					  * libosmo-mgcp: e1: fix memleaks in e1_recv_cb()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * update git URLs (git -> https; gitea)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 28 Jun 2022 18:50:25 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.9.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * TOS bits != DSCP
 | 
				
			||||||
 | 
					  * manual: don't define fig-bsc twice
 | 
				
			||||||
 | 
					  * switch from osmo_sock_set_dscp() to OSMO_SOCK_F_DSCP()
 | 
				
			||||||
 | 
					  * mgw: Add support for setting socket priority from VTY
 | 
				
			||||||
 | 
					  * manual: Include QoS chapter and add osmo-mgw specific example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Keith ]
 | 
				
			||||||
 | 
					  * Add vty command 'show mgcp active'
 | 
				
			||||||
 | 
					  * Log some useful messages at ERROR/INFO instead of DEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * send DLCX only once
 | 
				
			||||||
 | 
					  * tweak termination DLCX log msg
 | 
				
			||||||
 | 
					  * add osmo_mgcpc_ep_ci_get_remote_rtp_info()
 | 
				
			||||||
 | 
					  * check_rtp_destin(): clarify log msg
 | 
				
			||||||
 | 
					  * mgcp_client_fsm delete: set mgcp_client as ctx, not NULL
 | 
				
			||||||
 | 
					  * mgcp_client_endpoint_fsm: on term, still let conns wait for DLCX OK
 | 
				
			||||||
 | 
					  * mgcp_client_fsm: add missing log_subsys
 | 
				
			||||||
 | 
					  * mgcp_client: add logging on received MGCP messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_network: fix implicit address loopback
 | 
				
			||||||
 | 
					  * mgcp_common, mgcp_udp_send: make parameter buf const
 | 
				
			||||||
 | 
					  * mgcp_network: refactor MGCP_DUMMY_LOAD
 | 
				
			||||||
 | 
					  * mgcp_client: drop nunnecessary else statement
 | 
				
			||||||
 | 
					  * mgcp_client: fix error handling in mgcp message generation
 | 
				
			||||||
 | 
					  * mgcp_protocol: fix loop that sends dummy RTP packets
 | 
				
			||||||
 | 
					  * mgw_main: fix loop that resets all endpoints
 | 
				
			||||||
 | 
					  * mgcp_trunk: drop ws line
 | 
				
			||||||
 | 
					  * mgcp_ratectr: drop ws line
 | 
				
			||||||
 | 
					  * mgcp_ratectr: fix sourcecode formatting
 | 
				
			||||||
 | 
					  * mgcp_trunk: add value string for trunk type.
 | 
				
			||||||
 | 
					  * mgcp_ratectr: refactor rate counter and set group name
 | 
				
			||||||
 | 
					  * mgcp_protocol: forward declare mgcp_endpoint
 | 
				
			||||||
 | 
					  * mgcp_endp: make wildcarded detection separate
 | 
				
			||||||
 | 
					  * mgcp_protocol: refactor request handler array
 | 
				
			||||||
 | 
					  * mgcp_trunk: use unsigned int instead of int as trunk_nr
 | 
				
			||||||
 | 
					  * mgcp_protocol: refactor MGCP request handling
 | 
				
			||||||
 | 
					  * mgcp_ratectr: add stats items to monitor trunk usage
 | 
				
			||||||
 | 
					  * mgcp_msg: add trunk parameter to mgcp_check_param for logging
 | 
				
			||||||
 | 
					  * mgcp_protocol: refactor function create_response_with_sdp
 | 
				
			||||||
 | 
					  * mgcp_protocol: add support for wildcarded DLCX
 | 
				
			||||||
 | 
					  * remove struct member wildcarded_req from struct mgcp_endpoint
 | 
				
			||||||
 | 
					  * mgcp_lient: remove unsubstantial FIXME note
 | 
				
			||||||
 | 
					  * mgcp_protocol: assert endp when it becomes mandatory
 | 
				
			||||||
 | 
					  * mgcp_trunk: check MGW domain name earlier
 | 
				
			||||||
 | 
					  * mgcp_ratectr: add stats items to monitor trunk usage
 | 
				
			||||||
 | 
					  * mgcp_client: fix typo Initalize -> Initialize
 | 
				
			||||||
 | 
					  * mgcp_protocol: get rid of policy_cb and change_cb
 | 
				
			||||||
 | 
					  * mgcp_ratectr: do not set talloc destructor on library allocated item
 | 
				
			||||||
 | 
					  * mgcp_client: allow to reset endpoints on startup
 | 
				
			||||||
 | 
					  * mgcp_client_vty: remove unnecessary checks
 | 
				
			||||||
 | 
					  * mgcp_client: do not print (null) when address is ANY
 | 
				
			||||||
 | 
					  * mgcp_client: refactor function init_socket
 | 
				
			||||||
 | 
					  * libosmo-mgcp-client: extend the mgcp_client for MGW pooling
 | 
				
			||||||
 | 
					  * mgcp_client_vty: add missing docstrings
 | 
				
			||||||
 | 
					  * mgcp_client_vty: add OSMO_ASSERT on pool parameter
 | 
				
			||||||
 | 
					  * mgcp_client_vty: fix docstrings for mgw-pool
 | 
				
			||||||
 | 
					  * mgcp_client_vty: cosmetic: doc string should terminated with \n
 | 
				
			||||||
 | 
					  * mgcp_client_vty: fixing docstring
 | 
				
			||||||
 | 
					  * mgcp_ratectr: remove unusued rate counters
 | 
				
			||||||
 | 
					  * mgcp_client: fix typo in doxygen comment
 | 
				
			||||||
 | 
					  * mgcp_client: add MGW name as logging context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * Use new stat item/ctr getter APIs
 | 
				
			||||||
 | 
					  * constify arg in addr_is_any()
 | 
				
			||||||
 | 
					  * Define patch_ssrc as bool type
 | 
				
			||||||
 | 
					  * constify some function arg pointers
 | 
				
			||||||
 | 
					  * mgcp_network.c: Reorder some functions in file
 | 
				
			||||||
 | 
					  * mgcp_send_dummy: Check RTP destination is available before attempt tx
 | 
				
			||||||
 | 
					  * mgw: rx CRCX: Avoid sending dummy rtp if remote address not provided
 | 
				
			||||||
 | 
					  * Fail rx MDCX sendrecv with invalid remote addr
 | 
				
			||||||
 | 
					  * Take into account Marker bit when patching RTP stream
 | 
				
			||||||
 | 
					  * Use DLMGCP instead of DLGLOBAL in log lines
 | 
				
			||||||
 | 
					  * Fix attribute parsing on gcc 11.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ neels ]
 | 
				
			||||||
 | 
					  * Revert "mgcp_ratectr: add stats items to monitor trunk usage"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Daniel Willmann ]
 | 
				
			||||||
 | 
					  * contrib/jenkins: Use ASAN for osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * mgcp_client_vty: add missing NO_STR
 | 
				
			||||||
 | 
					  * Revert "Turn some compiler warnings into errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Eric ]
 | 
				
			||||||
 | 
					  * add vscode stuff to gitignore
 | 
				
			||||||
 | 
					  * configure.ac: fix maybe-uninitialized for clang
 | 
				
			||||||
 | 
					  * fix missing includes and forward declarations
 | 
				
			||||||
 | 
					  * rename do_retransmission
 | 
				
			||||||
 | 
					  * mgcp_sdp: fix potential leak
 | 
				
			||||||
 | 
					  * stats: make sanitizers happy
 | 
				
			||||||
 | 
					  * libosmo-mgcp: cleanup audio codex alloc
 | 
				
			||||||
 | 
					  * libosmo-mgcp: atomic rate counter group indexes
 | 
				
			||||||
 | 
					  * libosmo-mgcp: do not use the default msgb talloc context
 | 
				
			||||||
 | 
					  * globally lock the portrange when trying to grab a port to prep for multithreading
 | 
				
			||||||
 | 
					  * embed strings into structs
 | 
				
			||||||
 | 
					  * adjust talloc context
 | 
				
			||||||
 | 
					  * endp: do not cache cfg pointer
 | 
				
			||||||
 | 
					  * add modified .clang-format
 | 
				
			||||||
 | 
					  * rename strip_epname and find_specific_endpoint and make them available
 | 
				
			||||||
 | 
					  * fix mgcp_conn_free_all
 | 
				
			||||||
 | 
					  * fix up some docstrings that lost their dot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * libosmo-mgcp: use OSMO_STRLCPY_ARRAY in mgcp_codec_add()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 16 Nov 2021 16:59:21 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.8.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * attempt to fix RPM spec file after recent soversion bump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Harald Welte <laforge@osmocom.org>  Wed, 24 Feb 2021 10:56:17 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-mgw (1.8.0) unstable; urgency=medium
 | 
					osmo-mgw (1.8.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Harald Welte ]
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,13 +6,13 @@ Build-Depends: debhelper (>=9),
 | 
				
			|||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.5.0),
 | 
					               libosmocore-dev (>= 1.7.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.1.0),
 | 
					               libosmo-netif-dev (>= 1.2.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.1.0),
 | 
					               libosmo-abis-dev (>= 1.3.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.1.0)
 | 
					               osmo-gsm-manuals-dev (>= 1.3.0)
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
					Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
Vcs-Browser: https://git.osmocom.org/osmo-mgw/
 | 
					Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
Homepage: https://osmocom.org/projects/osmo-mgw
 | 
					Homepage: https://osmocom.org/projects/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw
 | 
					Package: 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-client8
 | 
					Package: libosmo-mgcp-client9
 | 
				
			||||||
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-client8 (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: libosmo-mgcp-client9 (= ${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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
					Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
				
			||||||
Upstream-Name: osmo-mgw
 | 
					Upstream-Name: osmo-mgw
 | 
				
			||||||
Source: git://git.osmocom.org/osmo-mgw
 | 
					Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files:     *
 | 
					Files:     *
 | 
				
			||||||
Copyright: 2009-2014 On-Waves
 | 
					Copyright: 2009-2014 On-Waves
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ mgcp
 | 
				
			|||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16000
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-tos 184
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					  sdp audio payload number 98
 | 
				
			||||||
  sdp audio payload name GSM
 | 
					  sdp audio payload name GSM
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ mgcp
 | 
				
			|||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16000
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-tos 184
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					  sdp audio payload number 98
 | 
				
			||||||
  sdp audio payload name GSM
 | 
					  sdp audio payload name GSM
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,6 +91,11 @@ the IP related aspects is nearly identical to the configuration of the virtual
 | 
				
			|||||||
trunk. However, it is important that the user assigns one of the E1 line numbers
 | 
					trunk. However, it is important that the user assigns one of the E1 line numbers
 | 
				
			||||||
that were configured under the e1_input node.
 | 
					that were configured under the e1_input node.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NOTE: The endpoint name that is used on MGCP level will include the trunk number,
 | 
				
			||||||
 | 
					not the E1 line number. For simplicity (and compatibility with OsmoBSC) it is
 | 
				
			||||||
 | 
					recommended to use equal numbers for trunk and E1 line. However, if required any
 | 
				
			||||||
 | 
					E1 line can be mapped flexible on any trunk as long as the mapping is bijective.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.Example: A typical configuration with one E1 trunk
 | 
					.Example: A typical configuration with one E1 trunk
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
e1_input
 | 
					e1_input
 | 
				
			||||||
@@ -101,7 +106,7 @@ mgcp
 | 
				
			|||||||
 rtp net-range 6000 6011
 | 
					 rtp net-range 6000 6011
 | 
				
			||||||
 rtp net-bind-ip 192.168.100.130
 | 
					 rtp net-bind-ip 192.168.100.130
 | 
				
			||||||
 rtp ip-probing
 | 
					 rtp ip-probing
 | 
				
			||||||
 rtp ip-tos 184
 | 
					 rtp ip-dscp 46
 | 
				
			||||||
 no rtp keep-alive
 | 
					 no rtp keep-alive
 | 
				
			||||||
 bind port 2428
 | 
					 bind port 2428
 | 
				
			||||||
 number endpoints 30
 | 
					 number endpoints 30
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ digraph G {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[fig-bsc]]
 | 
					[[fig-bsc-e1]]
 | 
				
			||||||
.Integration of legacy E1 BTS in AoIP network
 | 
					.Integration of legacy E1 BTS in AoIP network
 | 
				
			||||||
[graphviz]
 | 
					[graphviz]
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
@@ -107,8 +107,8 @@ We are planning to add further endpoint types for:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
You can find the OsmoMGW issue tracker and wiki online at
 | 
					You can find the OsmoMGW issue tracker and wiki online at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- https://osmocom.org/projects/osmomgw
 | 
					- https://osmocom.org/projects/osmo-mgw
 | 
				
			||||||
- https://osmocom.org/projects/osmomgw/wiki
 | 
					- https://osmocom.org/projects/osmo-mgw/wiki
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RFC 3435 for MGCP is located at
 | 
					RFC 3435 for MGCP is located at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										42
									
								
								doc/manuals/chapters/qos-example.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								doc/manuals/chapters/qos-example.adoc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					==== Full example of QoS for osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the below example we will show the full set of configuration required
 | 
				
			||||||
 | 
					for both DSCP and PCP differentiation of RTP traffic by osmo-mgw.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What we want to achieve in this example is the following configuration:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.DSCP and PCP assignments for osmo-mgw Abis downlink traffic in this example
 | 
				
			||||||
 | 
					[options="header",width="30%",cols="2,1,1"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					|Traffic      |DSCP|PCP
 | 
				
			||||||
 | 
					|RTP    |  46|  6
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. configure the osmo-mgw program to set the DSCP value
 | 
				
			||||||
 | 
					. configure an egrees QoS map to map from priority to PCP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example Step 1: add related VTY configuration to `osmo-mgw.cfg`
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					mgcp
 | 
				
			||||||
 | 
					 rtp ip-dscp 46
 | 
				
			||||||
 | 
					 rtp socket-priority 6
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Example Step 2: egress QoS map to map from socket priority to PCP values
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 5:5 6:6 7:7 <2>
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
 | 
				
			||||||
 | 
					<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also include the
 | 
				
			||||||
 | 
					    mapping 5:5 and 7:7 from the osmo-bsc example (see <<userman-osmobsc>>) here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NOTE:: The settings of the `ip` command are volatile and only active until
 | 
				
			||||||
 | 
					the next reboot (or the network device or VLAN is removed).  Please refer to
 | 
				
			||||||
 | 
					the documentation of your specific Linux distribution in order to find out how
 | 
				
			||||||
 | 
					to make such settings persistent by means of an `ifup` hook whenever the interface
 | 
				
			||||||
 | 
					comes up.  For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
 | 
				
			||||||
 | 
					script` (when using `network-scripts` and not NetworkManager).  For Debian or Ubuntu,
 | 
				
			||||||
 | 
					this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
 | 
				
			||||||
 | 
					script.
 | 
				
			||||||
@@ -24,6 +24,8 @@ include::{srcdir}/chapters/mgcp_extensions.adoc[]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/osmux/osmux.adoc[]
 | 
					include::./common/chapters/osmux/osmux.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/qos-dscp-pcp.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//include::{srcdir}/chapters/counters.adoc[]
 | 
					//include::{srcdir}/chapters/counters.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/vty_cpu_sched.adoc[]
 | 
					include::./common/chapters/vty_cpu_sched.adoc[]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ nobase_include_HEADERS = \
 | 
				
			|||||||
	osmocom/mgcp_client/mgcp_client.h \
 | 
						osmocom/mgcp_client/mgcp_client.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
				
			||||||
 | 
						osmocom/mgcp_client/mgcp_client_pool.h \
 | 
				
			||||||
	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 \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,4 +13,5 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_e1.h \
 | 
						mgcp_e1.h \
 | 
				
			||||||
	mgcp_network.h \
 | 
						mgcp_network.h \
 | 
				
			||||||
	mgcp_protocol.h \
 | 
						mgcp_protocol.h \
 | 
				
			||||||
 | 
						mgcp_iuup.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@
 | 
				
			|||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "mgcp_ratectr.h"
 | 
					#include "mgcp_ratectr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,8 +63,6 @@ struct mgcp_rtp_end;
 | 
				
			|||||||
#define MGCP_POLICY_REJECT	5
 | 
					#define MGCP_POLICY_REJECT	5
 | 
				
			||||||
#define MGCP_POLICY_DEFER	6
 | 
					#define MGCP_POLICY_DEFER	6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int (*mgcp_change)(struct mgcp_endpoint *endp, int state);
 | 
					 | 
				
			||||||
typedef int (*mgcp_policy)(struct mgcp_endpoint *endp, int state, const char *transaction_id);
 | 
					 | 
				
			||||||
typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
 | 
					typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
 | 
				
			||||||
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 | 
					typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,9 +93,10 @@ typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
 | 
				
			|||||||
 * This holds information on how to allocate ports
 | 
					 * This holds information on how to allocate ports
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct mgcp_port_range {
 | 
					struct mgcp_port_range {
 | 
				
			||||||
 | 
						pthread_mutex_t lock;
 | 
				
			||||||
	/* addr or NULL to fall-back to default */
 | 
						/* addr or NULL to fall-back to default */
 | 
				
			||||||
	char *bind_addr_v4;
 | 
						char bind_addr_v4[INET6_ADDRSTRLEN];
 | 
				
			||||||
	char *bind_addr_v6;
 | 
						char bind_addr_v6[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dynamically allocated */
 | 
						/* dynamically allocated */
 | 
				
			||||||
	int range_start;
 | 
						int range_start;
 | 
				
			||||||
@@ -129,9 +129,9 @@ enum mgcp_role {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct mgcp_config {
 | 
					struct mgcp_config {
 | 
				
			||||||
	int source_port;
 | 
						int source_port;
 | 
				
			||||||
	char *local_ip;
 | 
						char local_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
	char *source_addr;
 | 
						char source_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
	char *call_agent_addr;
 | 
						char call_agent_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RTP processing */
 | 
						/* RTP processing */
 | 
				
			||||||
	mgcp_processing rtp_processing_cb;
 | 
						mgcp_processing rtp_processing_cb;
 | 
				
			||||||
@@ -143,17 +143,14 @@ struct mgcp_config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct mgcp_port_range net_ports;
 | 
						struct mgcp_port_range net_ports;
 | 
				
			||||||
	int endp_dscp;
 | 
						int endp_dscp;
 | 
				
			||||||
 | 
						int endp_priority;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int force_ptime;
 | 
						int force_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_change change_cb;
 | 
					 | 
				
			||||||
	mgcp_policy policy_cb;
 | 
					 | 
				
			||||||
	mgcp_reset reset_cb;
 | 
						mgcp_reset reset_cb;
 | 
				
			||||||
	mgcp_rqnt rqnt_cb;
 | 
						mgcp_rqnt rqnt_cb;
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t last_call_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* list holding the trunks */
 | 
						/* list holding the trunks */
 | 
				
			||||||
	struct llist_head trunks;
 | 
						struct llist_head trunks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -162,7 +159,7 @@ struct mgcp_config {
 | 
				
			|||||||
	/* osmux translator: 0 means disabled, 1 means enabled */
 | 
						/* osmux translator: 0 means disabled, 1 means enabled */
 | 
				
			||||||
	int osmux;
 | 
						int osmux;
 | 
				
			||||||
	/* addr to bind the server to */
 | 
						/* addr to bind the server to */
 | 
				
			||||||
	char *osmux_addr;
 | 
						char osmux_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
	/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
 | 
						/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
 | 
				
			||||||
	 * the osmux socket is already initialized.
 | 
						 * the osmux socket is already initialized.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -208,5 +205,6 @@ 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);
 | 
					int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
				
			||||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, char *buf, int len);
 | 
							     uint8_t prio);
 | 
				
			||||||
 | 
					int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,3 +17,4 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
				
			|||||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@
 | 
				
			|||||||
#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/gsm/iuup.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
@@ -47,6 +48,7 @@ enum mgcp_conn_rtp_type {
 | 
				
			|||||||
	MGCP_RTP_DEFAULT	= 0,
 | 
						MGCP_RTP_DEFAULT	= 0,
 | 
				
			||||||
	MGCP_OSMUX_BSC,
 | 
						MGCP_OSMUX_BSC,
 | 
				
			||||||
	MGCP_OSMUX_BSC_NAT,
 | 
						MGCP_OSMUX_BSC_NAT,
 | 
				
			||||||
 | 
						MGCP_RTP_IUUP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
@@ -93,6 +95,14 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
		} stats;
 | 
							} stats;
 | 
				
			||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct osmo_iuup_instance *iui;
 | 
				
			||||||
 | 
							bool active_init; /* true: Send IuUP Init */
 | 
				
			||||||
 | 
							int rfci_id_no_data; /* RFCI Id for RFCI NO_DATA (-1 if not available) */
 | 
				
			||||||
 | 
							bool configured;
 | 
				
			||||||
 | 
							struct osmo_iuup_rnl_prim *init_ind;
 | 
				
			||||||
 | 
						} iuup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr_group *rate_ctr_group;
 | 
						struct rate_ctr_group *rate_ctr_group;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -176,6 +186,12 @@ static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
				
			|||||||
	return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
						return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
 | 
					static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return conn->type == MGCP_RTP_IUUP;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/gsm/i460_mux.h>
 | 
					#include <osmocom/gsm/i460_mux.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sockaddr;
 | 
					struct sockaddr;
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
@@ -96,9 +97,6 @@ struct mgcp_endpoint {
 | 
				
			|||||||
	/*! List of struct mgcp_conn, of the connections active on this endpoint */
 | 
						/*! List of struct mgcp_conn, of the connections active on this endpoint */
 | 
				
			||||||
	struct llist_head conns;
 | 
						struct llist_head conns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! Backpointer to the MGW configuration */
 | 
					 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! Backpointer to the trunk this endpoint belongs to */
 | 
						/*! Backpointer to the trunk this endpoint belongs to */
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,10 +109,6 @@ struct mgcp_endpoint {
 | 
				
			|||||||
	/*! Last MGCP response (in case re-transmission is required) */
 | 
						/*! Last MGCP response (in case re-transmission is required) */
 | 
				
			||||||
	char *last_response;
 | 
						char *last_response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! Memorize if this endpoint was choosen by the MGW (wildcarded, true)
 | 
					 | 
				
			||||||
	 *   or if the user has choosen the particular endpoint explicitly. */
 | 
					 | 
				
			||||||
	bool wildcarded_req;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
						/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -134,6 +128,7 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int ind
 | 
				
			|||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
					int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					bool mgcp_endp_is_wildcarded(const char *epname);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			||||||
					      const struct mgcp_trunk *trunk);
 | 
										      const struct mgcp_trunk *trunk);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			||||||
@@ -141,3 +136,7 @@ struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			|||||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
 | 
					bool mgcp_endp_avail(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_strip_name(char *epname_stripped, const char *epname,
 | 
				
			||||||
 | 
								 const struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
				
			||||||
 | 
								const struct mgcp_trunk *trunk);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								include/osmocom/mgcp/mgcp_iuup.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								include/osmocom/mgcp/mgcp_iuup.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					/* IuUP connection functionalitites */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Pau Espin Pedrol
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_dispatch_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);
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
@@ -25,10 +25,12 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
struct mgcp_parse_data;
 | 
					struct mgcp_parse_data;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,7 +41,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_osmux_cid(const char *line);
 | 
					int mgcp_parse_osmux_cid(const char *line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
 | 
					bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					/* The following constant defines an RTP dummy payload that is used for
 | 
				
			||||||
 | 
					 * "UDP Hole Punching" (NAT) */
 | 
				
			||||||
 | 
					static const char rtp_dummy_payload[] = { 0x23 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the data in a given message buffer matches the rtp dummy payload
 | 
				
			||||||
 | 
					 * defined above */
 | 
				
			||||||
 | 
					#define mgcp_is_rtp_dummy_payload(msg) \
 | 
				
			||||||
 | 
						(msgb_length(msg) == sizeof(rtp_dummy_payload) && \
 | 
				
			||||||
 | 
						memcmp(msgb_data(msg), rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RTP_BUF_SIZE	4096
 | 
					#define RTP_BUF_SIZE	4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_stream_state {
 | 
					struct mgcp_rtp_stream_state {
 | 
				
			||||||
@@ -25,7 +34,7 @@ struct mgcp_rtp_state {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* are we patching the SSRC value? */
 | 
							/* are we patching the SSRC value? */
 | 
				
			||||||
		int patch_ssrc;
 | 
							bool patch_ssrc;
 | 
				
			||||||
		/* original SSRC (to which we shall patch any different SSRC) */
 | 
							/* original SSRC (to which we shall patch any different SSRC) */
 | 
				
			||||||
		uint32_t orig_ssrc;
 | 
							uint32_t orig_ssrc;
 | 
				
			||||||
		/* offset to apply on the sequence number */
 | 
							/* offset to apply on the sequence number */
 | 
				
			||||||
@@ -61,8 +70,6 @@ struct mgcp_rtp_state {
 | 
				
			|||||||
	 * data is just re-used) */
 | 
						 * data is just re-used) */
 | 
				
			||||||
	uint16_t alt_rtp_tx_sequence;
 | 
						uint16_t alt_rtp_tx_sequence;
 | 
				
			||||||
	uint32_t alt_rtp_tx_ssrc;
 | 
						uint32_t alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_codec {
 | 
					struct mgcp_rtp_codec {
 | 
				
			||||||
@@ -72,8 +79,8 @@ struct mgcp_rtp_codec {
 | 
				
			|||||||
	uint32_t frame_duration_den;
 | 
						uint32_t frame_duration_den;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	char *audio_name;
 | 
						char audio_name[64];
 | 
				
			||||||
	char *subtype_name;
 | 
						char subtype_name[64];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool param_present;
 | 
						bool param_present;
 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
@@ -101,8 +108,8 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	uint32_t packet_duration_ms;
 | 
						uint32_t packet_duration_ms;
 | 
				
			||||||
	int maximum_packet_time; /* -1: not set */
 | 
						int maximum_packet_time; /* -1: not set */
 | 
				
			||||||
	char *fmtp_extra;
 | 
						char *fmtp_extra;
 | 
				
			||||||
	/* are we transmitting packets (1) or dropping (0) outbound packets */
 | 
						/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
				
			||||||
	int output_enabled;
 | 
						bool output_enabled;
 | 
				
			||||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
						/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
				
			||||||
	int force_output_ptime;
 | 
						int force_output_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -123,6 +130,8 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	char local_addr[INET6_ADDRSTRLEN];
 | 
						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;
 | 
				
			||||||
@@ -143,12 +152,11 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
 | 
				
			|||||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
					int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
				
			||||||
			   struct mgcp_conn_rtp *conn);
 | 
								   struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
 | 
					void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
 | 
				
			||||||
void mgcp_patch_and_count(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,
 | 
				
			||||||
			  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
								  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
				
			||||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_set_ip_tos(int fd, int tos);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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,
 | 
				
			||||||
@@ -164,6 +172,11 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
				
			|||||||
					  struct mgcp_conn_rtp *conn);
 | 
										  struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* internal RTP Annex A counting */
 | 
					/* internal RTP Annex A counting */
 | 
				
			||||||
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
					void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
				
			||||||
			const uint16_t seq, const int32_t transit,
 | 
								const uint16_t seq, const int32_t transit,
 | 
				
			||||||
			const uint32_t ssrc);
 | 
								const uint32_t ssrc, const bool marker_bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									 int id, int inc);
 | 
				
			||||||
 | 
					void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
				
			||||||
 | 
					uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
/* 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;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						char *epname;
 | 
				
			||||||
	char *trans;
 | 
						char *trans;
 | 
				
			||||||
	char *save;
 | 
						char *save;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -16,12 +16,15 @@ struct mgcp_lco {
 | 
				
			|||||||
	int pkt_period_max; /* time in ms */
 | 
						int pkt_period_max; /* time in ms */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *mgcp_debug_get_last_endpoint_name(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *get_lco_identifier(const char *options);
 | 
					char *get_lco_identifier(const char *options);
 | 
				
			||||||
int check_local_cx_options(void *ctx, const char *options);
 | 
					int check_local_cx_options(void *ctx, const char *options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_end;
 | 
					struct mgcp_rtp_end;
 | 
				
			||||||
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
					void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			||||||
			 struct mgcp_rtp_end *rtp);
 | 
								 struct mgcp_rtp_end *rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
 | 
					uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
				
			||||||
				  struct mgcp_rtp_end *rtp);
 | 
									  const struct mgcp_rtp_end *rtp);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global MCGP general rate counters */
 | 
					/* Global MCGP general rate counters */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	MGCP_GENERAL_RX_MSGS_TOTAL,
 | 
						MGCP_GENERAL_RX_MSGS_TOTAL,
 | 
				
			||||||
@@ -23,7 +22,6 @@ enum {
 | 
				
			|||||||
	MGCP_CRCX_FAIL_ALLOC_CONN,
 | 
						MGCP_CRCX_FAIL_ALLOC_CONN,
 | 
				
			||||||
	MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
						MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
				
			||||||
	MGCP_CRCX_FAIL_START_RTP,
 | 
						MGCP_CRCX_FAIL_START_RTP,
 | 
				
			||||||
	MGCP_CRCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_NO_OSMUX,
 | 
						MGCP_CRCX_FAIL_NO_OSMUX,
 | 
				
			||||||
	MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
 | 
						MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
 | 
				
			||||||
	MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
 | 
						MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
 | 
				
			||||||
@@ -46,21 +44,16 @@ enum {
 | 
				
			|||||||
	MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
 | 
						MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
 | 
				
			||||||
	MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
						MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
				
			||||||
	MGCP_MDCX_FAIL_START_RTP,
 | 
						MGCP_MDCX_FAIL_START_RTP,
 | 
				
			||||||
	MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_MDCX_DEFERRED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_AVAIL,
 | 
						MGCP_MDCX_FAIL_AVAIL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Trunk-global MCGP DLCX related rate counters */
 | 
					/* Trunk-global MCGP DLCX related rate counters */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	MGCP_DLCX_SUCCESS,
 | 
						MGCP_DLCX_SUCCESS,
 | 
				
			||||||
	MGCP_DLCX_FAIL_WILDCARD,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_NO_CONN,
 | 
						MGCP_DLCX_FAIL_NO_CONN,
 | 
				
			||||||
	MGCP_DLCX_FAIL_INVALID_CALLID,
 | 
						MGCP_DLCX_FAIL_INVALID_CALLID,
 | 
				
			||||||
	MGCP_DLCX_FAIL_INVALID_CONNID,
 | 
						MGCP_DLCX_FAIL_INVALID_CONNID,
 | 
				
			||||||
	MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 | 
						MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 | 
				
			||||||
	MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_DLCX_DEFERRED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_AVAIL,
 | 
						MGCP_DLCX_FAIL_AVAIL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,5 +84,24 @@ struct mgcp_ratectr_trunk {
 | 
				
			|||||||
	struct rate_ctr_group *e1_stats;
 | 
						struct rate_ctr_group *e1_stats;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr);
 | 
					struct mgcp_config;
 | 
				
			||||||
int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr);
 | 
					struct mgcp_trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_ratectr_global_alloc(struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					void mgcp_ratectr_global_free(struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trunk-global common stat items */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						TRUNK_STAT_ENDPOINTS_TOTAL,
 | 
				
			||||||
 | 
						TRUNK_STAT_ENDPOINTS_USED,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_stat_trunk {
 | 
				
			||||||
 | 
						/* Stat item group which contains general status values of the trunk. */
 | 
				
			||||||
 | 
						struct osmo_stat_item_group *common;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					void mgcp_stat_trunk_free(struct mgcp_trunk *trunk);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								include/osmocom/mgcp/mgcp_threads_queue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								include/osmocom/mgcp/mgcp_threads_queue.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Eric Wild
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <stdatomic.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct spsc {
 | 
				
			||||||
 | 
						atomic_uint readptr;
 | 
				
			||||||
 | 
						atomic_uint writeptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int efd_r, efd_w; /* eventfds used to block/notify readers/writers */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int count;
 | 
				
			||||||
 | 
						int size_per_buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *buf; /* buffer size count*size_per_buf */
 | 
				
			||||||
 | 
						uintptr_t data[0]; /* count sized array of pointers to size_per_buf chunks in buf array*/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct qchan {
 | 
				
			||||||
 | 
						struct spsc *a;
 | 
				
			||||||
 | 
						struct spsc *b;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool spsc_push(struct spsc *q, void *elem);
 | 
				
			||||||
 | 
					bool spsc_pop(struct spsc *q, void *elem);
 | 
				
			||||||
 | 
					ssize_t spsc_prep_pop(struct spsc *q);
 | 
				
			||||||
 | 
					int spsc_get_a_rdfd(struct qchan *q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct qchan spsc_chan_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf);
 | 
				
			||||||
 | 
					struct qchan spsc_chan_init_ex(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr_a,
 | 
				
			||||||
 | 
								       bool blockw_a, bool blockr_b, bool blockw_b);
 | 
				
			||||||
 | 
					void spsc_chan_close(struct qchan *q);
 | 
				
			||||||
@@ -2,24 +2,29 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#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_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, \
 | 
				
			||||||
     ## args)
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
enum mgcp_trunk_type {
 | 
					enum mgcp_trunk_type {
 | 
				
			||||||
	MGCP_TRUNK_VIRTUAL,
 | 
						MGCP_TRUNK_VIRTUAL,
 | 
				
			||||||
	MGCP_TRUNK_E1,
 | 
						MGCP_TRUNK_E1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string mgcp_trunk_type_strs[];
 | 
				
			||||||
 | 
					static inline const char *mgcp_trunk_type_strs_str(enum mgcp_trunk_type val)
 | 
				
			||||||
 | 
					{ return get_value_string(mgcp_trunk_type_strs, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_trunk {
 | 
					struct mgcp_trunk {
 | 
				
			||||||
	struct llist_head entry;
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
	enum mgcp_trunk_type trunk_type;
 | 
						enum mgcp_trunk_type trunk_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *audio_fmtp_extra;
 | 
						char *audio_fmtp_extra;
 | 
				
			||||||
@@ -49,8 +54,9 @@ struct mgcp_trunk {
 | 
				
			|||||||
	unsigned int number_endpoints;
 | 
						unsigned int number_endpoints;
 | 
				
			||||||
	struct mgcp_endpoint **endpoints;
 | 
						struct mgcp_endpoint **endpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* global rate counters to measure the trunks overall performance and health */
 | 
						/* rate counters and stat items to measure the trunks overall performance and health */
 | 
				
			||||||
	struct mgcp_ratectr_trunk ratectr;
 | 
						struct mgcp_ratectr_trunk ratectr;
 | 
				
			||||||
 | 
						struct mgcp_stat_trunk stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		/* Virtual trunk specific */
 | 
							/* Virtual trunk specific */
 | 
				
			||||||
@@ -69,11 +75,11 @@ struct mgcp_trunk {
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
 | 
					struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
 | 
				
			||||||
int mgcp_trunk_equip(struct mgcp_trunk *trunk);
 | 
					int mgcp_trunk_equip(struct mgcp_trunk *trunk);
 | 
				
			||||||
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
 | 
					struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
 | 
				
			||||||
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(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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ BUILT_SOURCES = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
noinst_HEADERS = \
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	mgcp_client_internal.h \
 | 
						mgcp_client_internal.h \
 | 
				
			||||||
 | 
						mgcp_client_pool_internal.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
 | 
					mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,15 @@ struct mgcp_client_conf {
 | 
				
			|||||||
	/* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.
 | 
						/* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.
 | 
				
			||||||
	 * If this is nonempty, the contained name will be used instead of 'mgw'. */
 | 
						 * If this is nonempty, the contained name will be used instead of 'mgw'. */
 | 
				
			||||||
	char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
 | 
						char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The user may configure certain endpoint names that are reset via DLCX
 | 
				
			||||||
 | 
						 * on startup. Usually this will be one wildcarded endpoint e.g.
 | 
				
			||||||
 | 
						 * 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.
 | 
				
			||||||
 | 
						 * 'ds/e1-0/s-3/su16-4' */
 | 
				
			||||||
 | 
						struct llist_head reset_epnames;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* human readable name / description */
 | 
				
			||||||
 | 
						char *description;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef unsigned int mgcp_trans_id_t;
 | 
					typedef unsigned int mgcp_trans_id_t;
 | 
				
			||||||
@@ -40,6 +49,7 @@ enum mgcp_codecs {
 | 
				
			|||||||
	CODEC_GSMHR_8000_1 = 111,
 | 
						CODEC_GSMHR_8000_1 = 111,
 | 
				
			||||||
	CODEC_AMR_8000_1 = 112,
 | 
						CODEC_AMR_8000_1 = 112,
 | 
				
			||||||
	CODEC_AMRWB_16000_1 = 113,
 | 
						CODEC_AMRWB_16000_1 = 113,
 | 
				
			||||||
 | 
						CODEC_IUFP = 96,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
/* Note: when new codec types are added, the corresponding value strings
 | 
					/* Note: when new codec types are added, the corresponding value strings
 | 
				
			||||||
 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
					 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
				
			||||||
@@ -130,6 +140,8 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
				
			|||||||
struct mgcp_client *mgcp_client_init(void *ctx,
 | 
					struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			||||||
				     struct mgcp_client_conf *conf);
 | 
									     struct mgcp_client_conf *conf);
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
				
			||||||
 | 
					int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
 | 
				
			||||||
 | 
					void mgcp_client_disconnect(struct mgcp_client *mgcp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
					const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
				
			||||||
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
 | 
					uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
 | 
				
			||||||
@@ -165,3 +177,5 @@ unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			|||||||
			     enum mgcp_codecs codec);
 | 
								     enum mgcp_codecs codec);
 | 
				
			||||||
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
					enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			||||||
				 unsigned int pt);
 | 
									 unsigned int pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *mgcp_client_name(const struct mgcp_client *mgcp);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,8 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
 | 
				
			|||||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);
 | 
				
			||||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid);
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_remote_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
					void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			||||||
			      enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
 | 
								      enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
 | 
				
			||||||
			      struct osmo_fsm_inst *notify,
 | 
								      struct osmo_fsm_inst *notify,
 | 
				
			||||||
@@ -45,6 +47,7 @@ void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
				
			|||||||
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
					const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct value_string osmo_mgcp_verb_names[];
 | 
					extern const struct value_string osmo_mgcp_verb_names[];
 | 
				
			||||||
static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
 | 
					static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,5 +69,6 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
					void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
 | 
					const char *mgcp_conn_get_ci(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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,12 +4,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define MSGB_CB_MGCP_TRANS_ID 0
 | 
					#define MSGB_CB_MGCP_TRANS_ID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Struct that holds one endpoint name */
 | 
				
			||||||
 | 
					struct reset_ep {
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
						char name[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client {
 | 
					struct mgcp_client {
 | 
				
			||||||
	struct mgcp_client_conf actual;
 | 
						struct mgcp_client_conf actual;
 | 
				
			||||||
	struct osmo_wqueue wq;
 | 
						struct osmo_wqueue wq;
 | 
				
			||||||
	mgcp_trans_id_t next_trans_id;
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
	struct llist_head inuse_endpoints;
 | 
						struct llist_head inuse_endpoints;
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_inuse_endpoint {
 | 
					struct mgcp_inuse_endpoint {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								include/osmocom/mgcp_client/mgcp_client_pool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								include/osmocom/mgcp_client/mgcp_client_pool.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client;
 | 
				
			||||||
 | 
					struct mgcp_client_pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
 | 
				
			||||||
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
				
			||||||
							
								
								
									
										45
									
								
								include/osmocom/mgcp_client/mgcp_client_pool_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/osmocom/mgcp_client/mgcp_client_pool_internal.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Struct to handle a member of a pool of MGWs. */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member {
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
 | 
				
			||||||
 | 
						 * the log. */
 | 
				
			||||||
 | 
						unsigned int nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* MGCP client configuration, this is not the running configuration, when mgcp_client_init() is executed, a
 | 
				
			||||||
 | 
						 * copy of this config is created. */
 | 
				
			||||||
 | 
						struct mgcp_client_conf conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* MGCP client descriptor, will be automatically allocated when mgcp_client_pool_connect() is called. (the MGCP
 | 
				
			||||||
 | 
						 * client is connected when this pointer is populated) */
 | 
				
			||||||
 | 
						struct mgcp_client *client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A pool member may be set as 'blocked' from the VTY, this means that the pool member may still work and serve
 | 
				
			||||||
 | 
						 * ongoing calls, but it won't be picked from the pool anymore. */
 | 
				
			||||||
 | 
						bool blocked;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reference counter to count how often this pool member is currently picked. */
 | 
				
			||||||
 | 
						unsigned int refcount;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Struct to handle a pool of MGWs. (Use _pool functions) */
 | 
				
			||||||
 | 
					struct mgcp_client_pool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
 | 
				
			||||||
 | 
						 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp_client_single;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A list that manages the pool members (see above) */
 | 
				
			||||||
 | 
						struct llist_head pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
 | 
				
			||||||
 | 
						 * mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						char *vty_indent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						struct cmd_node *vty_node;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
@@ -1,74 +0,0 @@
 | 
				
			|||||||
# ===========================================================================
 | 
					 | 
				
			||||||
#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
 | 
					 | 
				
			||||||
# ===========================================================================
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# SYNOPSIS
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# DESCRIPTION
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Check whether the given FLAG works with the current language's compiler
 | 
					 | 
				
			||||||
#   or gives an error.  (Warnings, however, are ignored)
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
 | 
					 | 
				
			||||||
#   success/failure.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   If EXTRA-FLAGS is defined, it is added to the current language's default
 | 
					 | 
				
			||||||
#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
 | 
					 | 
				
			||||||
#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
 | 
					 | 
				
			||||||
#   force the compiler to issue an error when a bad flag is given.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
 | 
					 | 
				
			||||||
#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# LICENSE
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
 | 
					 | 
				
			||||||
#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   This program is free software: you can redistribute it and/or modify it
 | 
					 | 
				
			||||||
#   under the terms of the GNU General Public License as published by the
 | 
					 | 
				
			||||||
#   Free Software Foundation, either version 3 of the License, or (at your
 | 
					 | 
				
			||||||
#   option) any later version.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   This program is distributed in the hope that it will be useful, but
 | 
					 | 
				
			||||||
#   WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 | 
					 | 
				
			||||||
#   Public License for more details.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   You should have received a copy of the GNU General Public License along
 | 
					 | 
				
			||||||
#   with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   As a special exception, the respective Autoconf Macro's copyright owner
 | 
					 | 
				
			||||||
#   gives unlimited permission to copy, distribute and modify the configure
 | 
					 | 
				
			||||||
#   scripts that are the output of Autoconf when processing the Macro. You
 | 
					 | 
				
			||||||
#   need not follow the terms of the GNU General Public License when using
 | 
					 | 
				
			||||||
#   or distributing such scripts, even though portions of the text of the
 | 
					 | 
				
			||||||
#   Macro appear in them. The GNU General Public License (GPL) does govern
 | 
					 | 
				
			||||||
#   all other use of the material that constitutes the Autoconf Macro.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#   This special exception to the GPL applies to versions of the Autoconf
 | 
					 | 
				
			||||||
#   Macro released by the Autoconf Archive. When you make and distribute a
 | 
					 | 
				
			||||||
#   modified version of the Autoconf Macro, you may extend this special
 | 
					 | 
				
			||||||
#   exception to the GPL to apply to your modified version as well.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#serial 4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
 | 
					 | 
				
			||||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
 | 
					 | 
				
			||||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
 | 
					 | 
				
			||||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
 | 
					 | 
				
			||||||
  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
 | 
					 | 
				
			||||||
  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
 | 
					 | 
				
			||||||
  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
 | 
					 | 
				
			||||||
    [AS_VAR_SET(CACHEVAR,[yes])],
 | 
					 | 
				
			||||||
    [AS_VAR_SET(CACHEVAR,[no])])
 | 
					 | 
				
			||||||
  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
 | 
					 | 
				
			||||||
AS_VAR_IF(CACHEVAR,yes,
 | 
					 | 
				
			||||||
  [m4_default([$2], :)],
 | 
					 | 
				
			||||||
  [m4_default([$3], :)])
 | 
					 | 
				
			||||||
AS_VAR_POPDEF([CACHEVAR])dnl
 | 
					 | 
				
			||||||
])dnl AX_CHECK_COMPILE_FLAGS
 | 
					 | 
				
			||||||
@@ -21,7 +21,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=8:0:0
 | 
					MGCP_CLIENT_LIBVERSION=10:0:1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -32,6 +32,7 @@ libosmo_mgcp_client_la_SOURCES = \
 | 
				
			|||||||
	mgcp_client_vty.c \
 | 
						mgcp_client_vty.c \
 | 
				
			||||||
	mgcp_client_fsm.c \
 | 
						mgcp_client_fsm.c \
 | 
				
			||||||
	mgcp_client_endpoint_fsm.c \
 | 
						mgcp_client_endpoint_fsm.c \
 | 
				
			||||||
 | 
						mgcp_client_pool.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
 | 
					libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,9 @@
 | 
				
			|||||||
#define OSMUX_CID_MAX 255 /* FIXME: use OSMUX_CID_MAX from libosmo-netif? */
 | 
					#define OSMUX_CID_MAX 255 /* FIXME: use OSMUX_CID_MAX from libosmo-netif? */
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPMGW(mgcp, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGP(DLMGCP, level, "MGW(%s) " fmt, mgcp_client_name(mgcp), ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Codec descripton for dynamic payload types (SDP) */
 | 
					/* Codec descripton for dynamic payload types (SDP) */
 | 
				
			||||||
const struct value_string osmo_mgcpc_codec_names[] = {
 | 
					const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			||||||
	{ CODEC_PCMU_8000_1, "PCMU/8000/1" },
 | 
						{ CODEC_PCMU_8000_1, "PCMU/8000/1" },
 | 
				
			||||||
@@ -56,6 +59,7 @@ const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			|||||||
	{ CODEC_GSMHR_8000_1, "GSM-HR-08/8000/1" },
 | 
						{ CODEC_GSMHR_8000_1, "GSM-HR-08/8000/1" },
 | 
				
			||||||
	{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
						{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
				
			||||||
	{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
						{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
				
			||||||
 | 
						{ CODEC_IUFP, "VND.3GPP.IUFP/16000" },
 | 
				
			||||||
	{ 0, NULL },
 | 
						{ 0, NULL },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,7 +73,6 @@ static char *extract_codec_name(const char *str)
 | 
				
			|||||||
	if (!str)
 | 
						if (!str)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME osmo_strlcpy */
 | 
					 | 
				
			||||||
	osmo_strlcpy(buf, str, sizeof(buf));
 | 
						osmo_strlcpy(buf, str, sizeof(buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < strlen(buf); i++) {
 | 
						for (i = 0; i < strlen(buf); i++) {
 | 
				
			||||||
@@ -190,7 +193,7 @@ enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			|||||||
	return pt;
 | 
						return pt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initalize MGCP client configuration struct with default values.
 | 
					/*! Initialize MGCP client configuration struct with default values.
 | 
				
			||||||
 *  \param[out] conf Client configuration.*/
 | 
					 *  \param[out] conf Client configuration.*/
 | 
				
			||||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
					void mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -201,6 +204,8 @@ void mgcp_client_conf_init(struct mgcp_client_conf *conf)
 | 
				
			|||||||
		.remote_addr = NULL,
 | 
							.remote_addr = NULL,
 | 
				
			||||||
		.remote_port = -1,
 | 
							.remote_port = -1,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&conf->reset_epnames);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mgcp_client_handle_response(struct mgcp_client *mgcp,
 | 
					static void mgcp_client_handle_response(struct mgcp_client *mgcp,
 | 
				
			||||||
@@ -208,14 +213,13 @@ static void mgcp_client_handle_response(struct mgcp_client *mgcp,
 | 
				
			|||||||
					struct mgcp_response *response)
 | 
										struct mgcp_response *response)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!pending) {
 | 
						if (!pending) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot handle NULL response\n");
 | 
				
			||||||
		     "Cannot handle NULL response\n");
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (pending->response_cb)
 | 
						if (pending->response_cb)
 | 
				
			||||||
		pending->response_cb(response, pending->priv);
 | 
							pending->response_cb(response, pending->priv);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "MGCP response ignored (NULL cb)\n");
 | 
							LOGPMGW(mgcp, LOGL_DEBUG, "MGCP response ignored (NULL cb)\n");
 | 
				
			||||||
	talloc_free(pending);
 | 
						talloc_free(pending);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -672,23 +676,25 @@ int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rc = mgcp_response_parse_head(r, msg);
 | 
						rc = mgcp_response_parse_head(r, msg);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
 | 
				
			||||||
		rc = 1;
 | 
							rc = 1;
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_DEBUG, "MGCP client: Rx %d %u %s\n",
 | 
				
			||||||
 | 
						     r->head.response_code, r->head.trans_id, r->head.comment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = parse_head_params(r);
 | 
						rc = parse_head_params(r);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
 | 
				
			||||||
		rc = 1;
 | 
							rc = 1;
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pending = mgcp_client_response_pending_get(mgcp, r->head.trans_id);
 | 
						pending = mgcp_client_response_pending_get(mgcp, r->head.trans_id);
 | 
				
			||||||
	if (!pending) {
 | 
						if (!pending) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot find matching MGCP transaction for trans_id %d\n",
 | 
				
			||||||
		     "Cannot find matching MGCP transaction for trans_id %d\n",
 | 
								r->head.trans_id);
 | 
				
			||||||
		     r->head.trans_id);
 | 
					 | 
				
			||||||
		rc = -ENOENT;
 | 
							rc = -ENOENT;
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -709,19 +715,19 @@ static int mgcp_do_read(struct osmo_fd *fd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
 | 
						msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
 | 
				
			||||||
	if (!msg) {
 | 
						if (!msg) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to allocate MGCP message.\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = read(fd->fd, msg->data, 4096 - 128);
 | 
						ret = read(fd->fd, msg->data, 4096 - 128);
 | 
				
			||||||
	if (ret <= 0) {
 | 
						if (ret <= 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to read: %s: %d='%s'\n", osmo_sock_get_name2(fd->fd),
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
 | 
				
			||||||
		     errno, strerror(errno));
 | 
							     osmo_sock_get_name2(fd->fd), errno, strerror(errno));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	} else if (ret > 4096 - 128) {
 | 
						} else if (ret > 4096 - 128) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -735,15 +741,17 @@ static int mgcp_do_read(struct osmo_fd *fd)
 | 
				
			|||||||
static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
 | 
					static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp = fd->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, 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_escape_str((const char*)msg->data, OSMO_MIN(42, msg->len)));
 | 
							osmo_sock_get_name2(fd->fd), msg->len,
 | 
				
			||||||
 | 
							osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = write(fd->fd, msg->data, msg->len);
 | 
						ret = write(fd->fd, msg->data, msg->len);
 | 
				
			||||||
	if (ret != msg->len)
 | 
						if (ret != msg->len)
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
 | 
				
			||||||
		     osmo_sock_get_name2(fd->fd), errno, strerror(errno),
 | 
								osmo_sock_get_name2(fd->fd), errno, strerror(errno),
 | 
				
			||||||
		     msg->len, osmo_escape_str((const char*)msg->data, OSMO_MIN(42, msg->len)));
 | 
								msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -751,6 +759,8 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
				     struct mgcp_client_conf *conf)
 | 
									     struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client *mgcp;
 | 
						struct mgcp_client *mgcp;
 | 
				
			||||||
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
						struct reset_ep *actual_reset_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp = talloc_zero(ctx, struct mgcp_client);
 | 
						mgcp = talloc_zero(ctx, struct mgcp_client);
 | 
				
			||||||
	if (!mgcp)
 | 
						if (!mgcp)
 | 
				
			||||||
@@ -774,62 +784,115 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	if (osmo_strlcpy(mgcp->actual.endpoint_domain_name, conf->endpoint_domain_name,
 | 
						if (osmo_strlcpy(mgcp->actual.endpoint_domain_name, conf->endpoint_domain_name,
 | 
				
			||||||
			 sizeof(mgcp->actual.endpoint_domain_name))
 | 
								 sizeof(mgcp->actual.endpoint_domain_name))
 | 
				
			||||||
	    >= sizeof(mgcp->actual.endpoint_domain_name)) {
 | 
						    >= sizeof(mgcp->actual.endpoint_domain_name)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP client: endpoint domain name is too long, max length is %zu: '%s'\n",
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "MGCP client: endpoint domain name is too long, max length is %zu: '%s'\n",
 | 
				
			||||||
		     sizeof(mgcp->actual.endpoint_domain_name) - 1, conf->endpoint_domain_name);
 | 
								sizeof(mgcp->actual.endpoint_domain_name) - 1, conf->endpoint_domain_name);
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));
 | 
						LOGPMGW(mgcp, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&mgcp->actual.reset_epnames);
 | 
				
			||||||
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
 | 
				
			||||||
 | 
							actual_reset_ep = talloc_memdup(mgcp, reset_ep, sizeof(*reset_ep));
 | 
				
			||||||
 | 
							llist_add_tail(&actual_reset_ep->list, &mgcp->actual.reset_epnames);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->description)
 | 
				
			||||||
 | 
							mgcp->actual.description = talloc_strdup(mgcp, conf->description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp;
 | 
						return mgcp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int init_socket(struct mgcp_client *mgcp)
 | 
					static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wq = &mgcp->wq;
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 100; i++) {
 | 
						for (i = 0; i < retry_n_ports + 1; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Initalize socket with the currently configured port
 | 
							/* Initialize socket with the currently configured port number */
 | 
				
			||||||
		 * number */
 | 
					 | 
				
			||||||
		rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
							rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
				
			||||||
					 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
										 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
				
			||||||
					 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
										 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
				
			||||||
		if (rc > 0)
 | 
							if (rc > 0)
 | 
				
			||||||
			return rc;
 | 
								return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* If there is a different port than the default port
 | 
							/* If there is a different port than the default port configured then we assume that the user has
 | 
				
			||||||
		 * configured then we assume that the user has choosen
 | 
							 * chosen that port conciously and we will not try to resolve this by silently choosing a different
 | 
				
			||||||
		 * that port conciously and we will not try to resolve
 | 
							 * port. */
 | 
				
			||||||
		 * this by silently choosing a different port. */
 | 
					 | 
				
			||||||
		if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)
 | 
							if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Choose a new port number to try next */
 | 
							if (i == retry_n_ports) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE,
 | 
								/* Last try failed */
 | 
				
			||||||
		     "MGCPGW failed to bind to %s:%u, retrying with port %u\n",
 | 
								LOGPMGW(mgcp, LOGL_NOTICE, "Failed to bind to %s:%d -- check configuration!\n",
 | 
				
			||||||
		     mgcp->actual.local_addr, mgcp->actual.local_port, mgcp->actual.local_port + 1);
 | 
								     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port);
 | 
				
			||||||
		mgcp->actual.local_port++;
 | 
								if (retry_n_ports == 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								/* Choose a new port number to try next */
 | 
				
			||||||
 | 
								LOGPMGW(mgcp, LOGL_NOTICE,
 | 
				
			||||||
 | 
								     "Failed to bind to %s:%d, retrying with port %d -- check configuration!\n",
 | 
				
			||||||
 | 
								     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
				
			||||||
 | 
								     mgcp->actual.local_port + 1);
 | 
				
			||||||
 | 
								mgcp->actual.local_port++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_FATAL, "MGCPGW failed to find a port to bind on %i times.\n", i);
 | 
						LOGPMGW(mgcp, LOGL_FATAL, "Failed to find a port to bind on %u times -- check configuration!\n", i);
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initalize client connection (opens socket only, no request is sent yet)
 | 
					/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
				
			||||||
 | 
					static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Format DLCX message (fire and forget) and send it off to the MGW */
 | 
				
			||||||
 | 
					static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msgb_dlcx;
 | 
				
			||||||
 | 
						struct mgcp_msg mgcp_msg_dlcx = {
 | 
				
			||||||
 | 
							.verb = MGCP_VERB_DLCX,
 | 
				
			||||||
 | 
							.presence = MGCP_MSG_PRESENCE_ENDPOINT,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
 | 
				
			||||||
 | 
						msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
 | 
				
			||||||
 | 
						mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
						if (rc > sizeof(endpoint) - 1) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
 | 
				
			||||||
 | 
								sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rc < 1) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return endpoint;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] retry_n_ports number of consecutive local ports that should be used to retry on failure.
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
					int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
						const char *epname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mgcp) {
 | 
						if (!mgcp) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
 | 
							LOGPMGW(mgcp, LOGL_FATAL, "Client not initialized properly\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -840,18 +903,25 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
						osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = init_socket(mgcp);
 | 
						rc = init_socket(mgcp, retry_n_ports);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_FATAL,
 | 
							LOGPMGW(mgcp, LOGL_FATAL,
 | 
				
			||||||
		     "Failed to initialize socket %s:%u -> %s:%u for MGCP GW: %s\n",
 | 
							     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
				
			||||||
		     mgcp->actual.local_addr, mgcp->actual.local_port,
 | 
							     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
				
			||||||
		     mgcp->actual.remote_addr, mgcp->actual.remote_port, strerror(errno));
 | 
							     mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
 | 
				
			||||||
 | 
							     strerror(errno));
 | 
				
			||||||
		goto error_close_fd;
 | 
							goto error_close_fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
						/* If configured, send a DLCX message to the endpoints that are configured to
 | 
				
			||||||
 | 
						 * be reset on startup. Usually this is a wildcarded endpoint. */
 | 
				
			||||||
 | 
						llist_for_each_entry(reset_ep, &mgcp->actual.reset_epnames, list) {
 | 
				
			||||||
 | 
							epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_INFO, "Sending DLCX to: %s\n", epname);
 | 
				
			||||||
 | 
							_mgcp_client_send_dlcx(mgcp, epname);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
error_close_fd:
 | 
					error_close_fd:
 | 
				
			||||||
	close(wq->bfd.fd);
 | 
						close(wq->bfd.fd);
 | 
				
			||||||
@@ -859,6 +929,35 @@ error_close_fd:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return mgcp_client_connect2(mgcp, 99);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Terminate client connection
 | 
				
			||||||
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
 | 
					void mgcp_client_disconnect(struct mgcp_client *mgcp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
 | 
						osmo_wqueue_clear(wq);
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
				
			||||||
 | 
						close(wq->bfd.fd);
 | 
				
			||||||
 | 
						wq->bfd.fd = -1;
 | 
				
			||||||
 | 
						if (osmo_fd_is_registered(&wq->bfd))
 | 
				
			||||||
 | 
							osmo_fd_unregister(&wq->bfd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get the IP-Aaddress of the associated MGW as string.
 | 
					/*! Get the IP-Aaddress of the associated MGW as string.
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns a pointer to the address string. */
 | 
					 *  \returns a pointer to the address string. */
 | 
				
			||||||
@@ -891,24 +990,6 @@ const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp)
 | 
				
			|||||||
	return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
 | 
						return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
 | 
					 | 
				
			||||||
	if (rc > sizeof(endpoint) - 1) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
 | 
					 | 
				
			||||||
		     sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (rc < 1) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return endpoint;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Compose endpoint name for a wildcarded request to the virtual trunk
 | 
					/*! Compose endpoint name for a wildcarded request to the virtual trunk
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */
 | 
					 *  \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */
 | 
				
			||||||
@@ -940,7 +1021,7 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
 | 
				
			|||||||
	    talloc_asprintf(ctx, "ds/e1-%u/s-%u/su%u-%u@%s", trunk_id, ts, rate, offset,
 | 
						    talloc_asprintf(ctx, "ds/e1-%u/s-%u/su%u-%u@%s", trunk_id, ts, rate, offset,
 | 
				
			||||||
			    mgcp_client_endpoint_domain(mgcp));
 | 
								    mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
	if (!epname) {
 | 
						if (!epname) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP e1-endpoint name!\n");
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP e1-endpoint name!\n");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -950,9 +1031,9 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
 | 
				
			|||||||
			rate_offs_valid = true;
 | 
								rate_offs_valid = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!rate_offs_valid) {
 | 
						if (!rate_offs_valid) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Cannot compose MGCP e1-endpoint name (%s), rate(%u)/offset(%u) combination is invalid!\n", epname,
 | 
								"Cannot compose MGCP e1-endpoint name (%s), rate(%u)/offset(%u) combination is invalid!\n",
 | 
				
			||||||
		     rate, offset);
 | 
								epname, rate, offset);
 | 
				
			||||||
		talloc_free(epname);
 | 
							talloc_free(epname);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -960,8 +1041,9 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
 | 
				
			|||||||
	/* An E1 line has a maximum of 32 timeslots, while the first (ts=0) is
 | 
						/* An E1 line has a maximum of 32 timeslots, while the first (ts=0) is
 | 
				
			||||||
	 * reserverd for framing and alignment, so we can not use it here. */
 | 
						 * reserverd for framing and alignment, so we can not use it here. */
 | 
				
			||||||
	if (ts == 0 || ts > NUM_E1_TS-1) {
 | 
						if (ts == 0 || ts > NUM_E1_TS-1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Cannot compose MGCP e1-endpoint name (%s), E1-timeslot number (%u) is invalid!\n", epname, ts);
 | 
								"Cannot compose MGCP e1-endpoint name (%s), E1-timeslot number (%u) is invalid!\n",
 | 
				
			||||||
 | 
								epname, ts);
 | 
				
			||||||
		talloc_free(epname);
 | 
							talloc_free(epname);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -989,7 +1071,7 @@ struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			|||||||
	return pending;
 | 
						return pending;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send the MGCP message in msg to the MGCP GW and handle a response with
 | 
					/* Send the MGCP message in msg to the MGW and handle a response with
 | 
				
			||||||
 * response_cb. NOTE: the response_cb still needs to call
 | 
					 * response_cb. NOTE: the response_cb still needs to call
 | 
				
			||||||
 * mgcp_response_parse_params(response) to get the parsed parameters -- to
 | 
					 * mgcp_response_parse_params(response) to get the parsed parameters -- to
 | 
				
			||||||
 * potentially save some CPU cycles, only the head line has been parsed when
 | 
					 * potentially save some CPU cycles, only the head line has been parsed when
 | 
				
			||||||
@@ -1006,8 +1088,8 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
 | 
						trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
 | 
				
			||||||
	if (!trans_id) {
 | 
						if (!trans_id) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Unset transaction id in mgcp send request\n");
 | 
								"Unset transaction id in mgcp send request\n");
 | 
				
			||||||
		talloc_free(msg);
 | 
							talloc_free(msg);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1022,9 +1104,9 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msgb_l2len(msg) > 4096) {
 | 
						if (msgb_l2len(msg) > 4096) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Cannot send, MGCP message too large: %u\n",
 | 
								"Cannot send, MGCP message too large: %u\n",
 | 
				
			||||||
		     msgb_l2len(msg));
 | 
								msgb_l2len(msg));
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		rc = -EINVAL;
 | 
							rc = -EINVAL;
 | 
				
			||||||
		goto mgcp_tx_error;
 | 
							goto mgcp_tx_error;
 | 
				
			||||||
@@ -1032,12 +1114,12 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
 | 
						rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
 | 
				
			||||||
	if (rc) {
 | 
						if (rc) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_FATAL, "Could not queue message to MGCP GW\n");
 | 
							LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		goto mgcp_tx_error;
 | 
							goto mgcp_tx_error;
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Queued %u bytes for MGCP GW\n",
 | 
							LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
 | 
				
			||||||
		     msgb_l2len(msg));
 | 
								msgb_l2len(msg));
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mgcp_tx_error:
 | 
					mgcp_tx_error:
 | 
				
			||||||
@@ -1064,10 +1146,10 @@ int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id)
 | 
				
			|||||||
	struct mgcp_response_pending *pending = mgcp_client_response_pending_get(mgcp, trans_id);
 | 
						struct mgcp_response_pending *pending = mgcp_client_response_pending_get(mgcp, trans_id);
 | 
				
			||||||
	if (!pending) {
 | 
						if (!pending) {
 | 
				
			||||||
		/*! Note: it is not harmful to cancel a transaction twice. */
 | 
							/*! Note: it is not harmful to cancel a transaction twice. */
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot cancel, no such transaction: %u\n", trans_id);
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Cannot cancel, no such transaction: %u\n", trans_id);
 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "Canceled transaction %u\n", trans_id);
 | 
						LOGPMGW(mgcp, LOGL_DEBUG, "Canceled transaction %u\n", trans_id);
 | 
				
			||||||
	talloc_free(pending);
 | 
						talloc_free(pending);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
	/*! We don't really need to clean up the wqueue: In all sane cases, the msgb has already been sent
 | 
						/*! We don't really need to clean up the wqueue: In all sane cases, the msgb has already been sent
 | 
				
			||||||
@@ -1105,30 +1187,40 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	const char *codec;
 | 
						const char *codec;
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc += msgb_printf(msg, "L:");
 | 
						rc |= msgb_printf(msg, "L:");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->ptime)
 | 
						if (mgcp_msg->ptime)
 | 
				
			||||||
		rc += msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
 | 
							rc |= msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->codecs_len) {
 | 
						if (mgcp_msg->codecs_len) {
 | 
				
			||||||
		rc += msgb_printf(msg, " a:");
 | 
							rc |= msgb_printf(msg, " a:");
 | 
				
			||||||
		for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
							for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
			pt = mgcp_msg->codecs[i];
 | 
								pt = mgcp_msg->codecs[i];
 | 
				
			||||||
			codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
			OSMO_ASSERT(codec);
 | 
								if (!codec) {
 | 
				
			||||||
			rc += msgb_printf(msg, "%s", extract_codec_name(codec));
 | 
									msgb_free(msg);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rc |= msgb_printf(msg, "%s", extract_codec_name(codec));
 | 
				
			||||||
			if (i < mgcp_msg->codecs_len - 1)
 | 
								if (i < mgcp_msg->codecs_len - 1)
 | 
				
			||||||
				rc += msgb_printf(msg, ";");
 | 
									rc |= msgb_printf(msg, ";");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rc += msgb_printf(msg, ",");
 | 
							rc |= msgb_printf(msg, ",");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc += msgb_printf(msg, " nt:IN\r\n");
 | 
						rc |= msgb_printf(msg, " nt:IN\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "message buffer to small, can not generate MGCP message (LCO)\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
 | 
					/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
 | 
				
			||||||
@@ -1142,64 +1234,64 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add separator to mark the beginning of the SDP block */
 | 
						/* Add separator to mark the beginning of the SDP block */
 | 
				
			||||||
	rc += msgb_printf(msg, "\r\n");
 | 
						rc |= msgb_printf(msg, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add SDP protocol version */
 | 
						/* Add SDP protocol version */
 | 
				
			||||||
	rc += msgb_printf(msg, "v=0\r\n");
 | 
						rc |= msgb_printf(msg, "v=0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Determine local IP-Address */
 | 
						/* Determine local IP-Address */
 | 
				
			||||||
	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
						if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Could not determine local IP-Address!\n");
 | 
								"Could not determine local IP-Address!\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	local_ip_family = osmo_ip_str_type(local_ip);
 | 
						local_ip_family = osmo_ip_str_type(local_ip);
 | 
				
			||||||
	if (local_ip_family == AF_UNSPEC) {
 | 
						if (local_ip_family == AF_UNSPEC) {
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
						audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
				
			||||||
	if (audio_ip_family == AF_UNSPEC) {
 | 
						if (audio_ip_family == AF_UNSPEC) {
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add owner/creator (SDP) */
 | 
						/* Add owner/creator (SDP) */
 | 
				
			||||||
	rc += msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
						rc |= msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
				
			||||||
			  local_ip_family == AF_INET6 ? '6' : '4',
 | 
								  local_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
			  local_ip);
 | 
								  local_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add session name (none) */
 | 
						/* Add session name (none) */
 | 
				
			||||||
	rc += msgb_printf(msg, "s=-\r\n");
 | 
						rc |= msgb_printf(msg, "s=-\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add RTP address and port */
 | 
						/* Add RTP address and port */
 | 
				
			||||||
	if (mgcp_msg->audio_port == 0) {
 | 
						if (mgcp_msg->audio_port == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Invalid port number, can not generate MGCP message\n");
 | 
								"Invalid port number, can not generate MGCP message\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strlen(mgcp_msg->audio_ip) <= 0) {
 | 
						if (strlen(mgcp_msg->audio_ip) <= 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "Empty ip address, can not generate MGCP message\n");
 | 
								"Empty ip address, can not generate MGCP message\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc += msgb_printf(msg, "c=IN IP%c %s\r\n",
 | 
						rc |= msgb_printf(msg, "c=IN IP%c %s\r\n",
 | 
				
			||||||
			  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
								  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
			  mgcp_msg->audio_ip);
 | 
								  mgcp_msg->audio_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add time description, active time (SDP) */
 | 
						/* Add time description, active time (SDP) */
 | 
				
			||||||
	rc += msgb_printf(msg, "t=0 0\r\n");
 | 
						rc |= msgb_printf(msg, "t=0 0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc += msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
 | 
						rc |= msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
 | 
				
			||||||
	for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
						for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
		pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
							pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
		rc += msgb_printf(msg, " %u", pt);
 | 
							rc |= msgb_printf(msg, " %u", pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc += msgb_printf(msg, "\r\n");
 | 
						rc |= msgb_printf(msg, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add optional codec parameters (fmtp) */
 | 
						/* Add optional codec parameters (fmtp) */
 | 
				
			||||||
	if (mgcp_msg->param_present) {
 | 
						if (mgcp_msg->param_present) {
 | 
				
			||||||
@@ -1209,9 +1301,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
				   continue;
 | 
									   continue;
 | 
				
			||||||
			pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
								pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
			if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
 | 
								if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
				rc += msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
 | 
									rc |= msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
 | 
				
			||||||
			else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
 | 
								else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
				rc += msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
 | 
									rc |= msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1226,16 +1318,25 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
			OSMO_ASSERT(codec);
 | 
								if (!codec) {
 | 
				
			||||||
 | 
									msgb_free(msg);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			rc += msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
 | 
								rc |= msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_msg->ptime)
 | 
						if (mgcp_msg->ptime)
 | 
				
			||||||
		rc += msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
 | 
							rc |= msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message (SDP)\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOBUFS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Generate an MGCP message
 | 
					/*! Generate an MGCP message
 | 
				
			||||||
@@ -1248,7 +1349,6 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	uint32_t mandatory_mask;
 | 
						uint32_t mandatory_mask;
 | 
				
			||||||
	struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
 | 
						struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	int rc_sdp;
 | 
					 | 
				
			||||||
	bool use_sdp = false;
 | 
						bool use_sdp = false;
 | 
				
			||||||
	char buf[32];
 | 
						char buf[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1259,35 +1359,34 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	switch (mgcp_msg->verb) {
 | 
						switch (mgcp_msg->verb) {
 | 
				
			||||||
	case MGCP_VERB_CRCX:
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
		mandatory_mask = MGCP_CRCX_MANDATORY;
 | 
							mandatory_mask = MGCP_CRCX_MANDATORY;
 | 
				
			||||||
		rc += msgb_printf(msg, "CRCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "CRCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_MDCX:
 | 
						case MGCP_VERB_MDCX:
 | 
				
			||||||
		mandatory_mask = MGCP_MDCX_MANDATORY;
 | 
							mandatory_mask = MGCP_MDCX_MANDATORY;
 | 
				
			||||||
		rc += msgb_printf(msg, "MDCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "MDCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_DLCX:
 | 
						case MGCP_VERB_DLCX:
 | 
				
			||||||
		mandatory_mask = MGCP_DLCX_MANDATORY;
 | 
							mandatory_mask = MGCP_DLCX_MANDATORY;
 | 
				
			||||||
		rc += msgb_printf(msg, "DLCX %u", trans_id);
 | 
							rc |= msgb_printf(msg, "DLCX %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_AUEP:
 | 
						case MGCP_VERB_AUEP:
 | 
				
			||||||
		mandatory_mask = MGCP_AUEP_MANDATORY;
 | 
							mandatory_mask = MGCP_AUEP_MANDATORY;
 | 
				
			||||||
		rc += msgb_printf(msg, "AUEP %u", trans_id);
 | 
							rc |= msgb_printf(msg, "AUEP %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_VERB_RSIP:
 | 
						case MGCP_VERB_RSIP:
 | 
				
			||||||
		mandatory_mask = MGCP_RSIP_MANDATORY;
 | 
							mandatory_mask = MGCP_RSIP_MANDATORY;
 | 
				
			||||||
		rc += msgb_printf(msg, "RSIP %u", trans_id);
 | 
							rc |= msgb_printf(msg, "RSIP %u", trans_id);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Invalid command verb, can not generate MGCP message\n");
 | 
				
			||||||
		     "Invalid command verb, can not generate MGCP message\n");
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if mandatory fields are missing */
 | 
						/* Check if mandatory fields are missing */
 | 
				
			||||||
	if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
 | 
						if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
		     "One or more missing mandatory fields, can not generate MGCP message\n");
 | 
								"One or more missing mandatory fields, can not generate MGCP message\n");
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1295,39 +1394,37 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	/* Add endpoint name */
 | 
						/* Add endpoint name */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
 | 
				
			||||||
		if (strlen(mgcp_msg->endpoint) <= 0) {
 | 
							if (strlen(mgcp_msg->endpoint) <= 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Empty endpoint name, can not generate MGCP message\n");
 | 
				
			||||||
			     "Empty endpoint name, can not generate MGCP message\n");
 | 
					 | 
				
			||||||
			msgb_free(msg);
 | 
								msgb_free(msg);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (strstr(mgcp_msg->endpoint, "@") == NULL) {
 | 
							if (strstr(mgcp_msg->endpoint, "@") == NULL) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPMGW(mgcp, LOGL_ERROR,
 | 
				
			||||||
			     "Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
									"Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
				
			||||||
			     mgcp_msg->endpoint);
 | 
									mgcp_msg->endpoint);
 | 
				
			||||||
			msgb_free(msg);
 | 
								msgb_free(msg);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
 | 
							rc |= msgb_printf(msg, " %s", mgcp_msg->endpoint);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add protocol version */
 | 
						/* Add protocol version */
 | 
				
			||||||
	rc += msgb_printf(msg, " MGCP 1.0\r\n");
 | 
						rc |= msgb_printf(msg, " MGCP 1.0\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add call id */
 | 
						/* Add call id */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
 | 
				
			||||||
		rc += msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
 | 
							rc |= msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add connection id */
 | 
						/* Add connection id */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
 | 
				
			||||||
		if (strlen(mgcp_msg->conn_id) <= 0) {
 | 
							if (strlen(mgcp_msg->conn_id) <= 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Empty connection id, can not generate MGCP message\n");
 | 
				
			||||||
			     "Empty connection id, can not generate MGCP message\n");
 | 
					 | 
				
			||||||
			msgb_free(msg);
 | 
								msgb_free(msg);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
 | 
							rc |= msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Using SDP makes sense when a valid IP/Port combination is specifiec,
 | 
						/* Using SDP makes sense when a valid IP/Port combination is specifiec,
 | 
				
			||||||
@@ -1339,33 +1436,34 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	/* Add local connection options (LCO) */
 | 
						/* Add local connection options (LCO) */
 | 
				
			||||||
	if (!use_sdp
 | 
						if (!use_sdp
 | 
				
			||||||
	    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
						    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
				
			||||||
		|| mgcp_msg->verb == MGCP_VERB_MDCX))
 | 
							|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
				
			||||||
		rc += add_lco(msg, mgcp_msg);
 | 
						        if (add_lco(msg, mgcp_msg) < 0)
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add mode */
 | 
						/* Add mode */
 | 
				
			||||||
	if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
 | 
						if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
 | 
				
			||||||
		rc +=
 | 
							rc |=
 | 
				
			||||||
		    msgb_printf(msg, "M: %s\r\n",
 | 
							    msgb_printf(msg, "M: %s\r\n",
 | 
				
			||||||
				mgcp_client_cmode_name(mgcp_msg->conn_mode));
 | 
									mgcp_client_cmode_name(mgcp_msg->conn_mode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add X-Osmo-IGN */
 | 
						/* Add X-Osmo-IGN */
 | 
				
			||||||
	if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
 | 
						if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
 | 
				
			||||||
	    && (mgcp_msg->x_osmo_ign != 0))
 | 
						    && (mgcp_msg->x_osmo_ign != 0))
 | 
				
			||||||
		rc +=
 | 
							rc |=
 | 
				
			||||||
		    msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
							    msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
									mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add X-Osmo-Osmux */
 | 
						/* Add X-Osmo-Osmux */
 | 
				
			||||||
	if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID)) {
 | 
						if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID)) {
 | 
				
			||||||
		if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
 | 
							if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPMGW(mgcp, LOGL_ERROR, "Wrong Osmux CID %d, can not generate MGCP message\n",
 | 
				
			||||||
			     "Wrong Osmux CID %d, can not generate MGCP message\n",
 | 
									mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
			     mgcp_msg->x_osmo_osmux_cid);
 | 
					 | 
				
			||||||
			msgb_free(msg);
 | 
								msgb_free(msg);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
 | 
							snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
		rc +=
 | 
							rc |=
 | 
				
			||||||
		    msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
 | 
							    msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
 | 
									mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1375,16 +1473,12 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	if (use_sdp
 | 
						if (use_sdp
 | 
				
			||||||
	    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
						    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
				
			||||||
		|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
							|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
 | 
				
			||||||
		rc_sdp = add_sdp(msg, mgcp_msg, mgcp);
 | 
						        if (add_sdp(msg, mgcp_msg, mgcp) < 0)
 | 
				
			||||||
		if (rc_sdp == -2)
 | 
					 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			rc += rc_sdp;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc != 0) {
 | 
						if (rc != 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message\n");
 | 
				
			||||||
		     "message buffer to small, can not generate MGCP message\n");
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		msg = NULL;
 | 
							msg = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1400,7 +1494,7 @@ mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg)
 | 
				
			|||||||
	return (mgcp_trans_id_t)msg->cb[MSGB_CB_MGCP_TRANS_ID];
 | 
						return (mgcp_trans_id_t)msg->cb[MSGB_CB_MGCP_TRANS_ID];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get the configuration parameters a given MGCP client instance
 | 
					/*! Get the configuration parameters for a given MGCP client instance
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns configuration */
 | 
					 *  \returns configuration */
 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
 | 
					struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
 | 
				
			||||||
@@ -1416,3 +1510,22 @@ const struct value_string mgcp_client_connection_mode_strs[] = {
 | 
				
			|||||||
	{ MGCP_CONN_LOOPBACK, "loopback" },
 | 
						{ MGCP_CONN_LOOPBACK, "loopback" },
 | 
				
			||||||
	{ 0, NULL }
 | 
						{ 0, NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get MGCP client instance name (VTY).
 | 
				
			||||||
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \returns MGCP client name.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  The user can only modify the name of an MGCP client instance when it is
 | 
				
			||||||
 | 
					 *  part of a pool. For single MGCP client instances and MGCP client instance
 | 
				
			||||||
 | 
					 *  where no description is set via the VTY, the MGW domain name will be used
 | 
				
			||||||
 | 
					 *  as name. */
 | 
				
			||||||
 | 
					const char *mgcp_client_name(const struct mgcp_client *mgcp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!mgcp)
 | 
				
			||||||
 | 
							return "(null)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp->actual.description)
 | 
				
			||||||
 | 
							return mgcp->actual.description;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return mgcp_client_endpoint_domain(mgcp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define LOG_CI(ci, level, fmt, args...) do { \
 | 
					#define LOG_CI(ci, level, fmt, args...) do { \
 | 
				
			||||||
	if (!ci || !ci->ep) \
 | 
						if (!ci || !ci->ep) \
 | 
				
			||||||
		LOGP(DLGLOBAL, level, "(unknown MGW endpoint) " fmt, ## args); \
 | 
							LOGP(DLMGCP, level, "(unknown MGW endpoint) " fmt, ## args); \
 | 
				
			||||||
	else \
 | 
						else \
 | 
				
			||||||
		LOG_MGCPC_EP(ci->ep, level, "CI[%d] %s%s%s: " fmt, \
 | 
							LOG_MGCPC_EP(ci->ep, level, "CI[%d] %s%s%s: " fmt, \
 | 
				
			||||||
			(int)(ci - ci->ep->ci), \
 | 
								(int)(ci - ci->ep->ci), \
 | 
				
			||||||
@@ -216,6 +216,13 @@ const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			|||||||
	return ci->mgcp_ci_str;
 | 
						return ci->mgcp_ci_str;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ep)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return ep->mgcp_client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
 | 
					static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
					static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
				
			||||||
@@ -508,7 +515,8 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			|||||||
	osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
 | 
						osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
 | 
					/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
 | 
				
			||||||
 | 
					 * returned by the last CRCX-OK / MDCX-OK message. */
 | 
				
			||||||
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
 | 
					const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
 | 
						ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
 | 
				
			||||||
@@ -519,6 +527,16 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
 | 
				
			|||||||
	return &ci->rtp_info;
 | 
						return &ci->rtp_info;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Return the MGW's remote RTP port information for this connection, i.e. the remote RTP port that the MGW is sending
 | 
				
			||||||
 | 
					 * to, as sent to the MGW by the last CRCX / MDCX message. */
 | 
				
			||||||
 | 
					const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_remote_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
 | 
				
			||||||
 | 
						if (!ci)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return &ci->verb_info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
 | 
					/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
 | 
				
			||||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -605,7 +623,7 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			|||||||
	ci = osmo_mgcpc_ep_check_ci(ci);
 | 
						ci = osmo_mgcpc_ep_check_ci(ci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ci) {
 | 
						if (!ci) {
 | 
				
			||||||
		LOGP(DLGLOBAL, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");
 | 
				
			||||||
		goto dispatch_error;
 | 
							goto dispatch_error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!verb_info && verb != MGCP_VERB_DLCX) {
 | 
						if (!verb_info && verb != MGCP_VERB_DLCX) {
 | 
				
			||||||
@@ -979,6 +997,34 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We want the mgcp_client_fsm to still stick around until it received the DLCX "OK" responses from the MGW. So
 | 
				
			||||||
 | 
						 * it should not dealloc along with this ep_fsm instance. Instead, signal DLCX for each conn on the endpoint,
 | 
				
			||||||
 | 
						 * and detach the mgcp_client_fsm from being a child-fsm.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * After mgcp_conn_delete(), an mgcp_client_fsm instance goes into ST_DLCX_RESP, which waits up to 4 seconds for
 | 
				
			||||||
 | 
						 * a DLCX OK. If none is received in that time, the instance terminates. So cleanup of the instance is
 | 
				
			||||||
 | 
						 * guaranteed. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
 | 
				
			||||||
 | 
							struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!ci->occupied || !ci->mgcp_client_fi)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* mgcp_conn_delete() unlinks itself from this parent FSM implicitly and waits for the DLCX OK. */
 | 
				
			||||||
 | 
							mgcp_conn_delete(ci->mgcp_client_fi);
 | 
				
			||||||
 | 
							/* Forget all about this ci */
 | 
				
			||||||
 | 
							*ci = (struct osmo_mgcpc_ep_ci){
 | 
				
			||||||
 | 
								.ep = ep,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct osmo_fsm osmo_mgcpc_ep_fsm = {
 | 
					static struct osmo_fsm osmo_mgcpc_ep_fsm = {
 | 
				
			||||||
	.name = "mgw-endp",
 | 
						.name = "mgw-endp",
 | 
				
			||||||
	.states = osmo_mgcpc_ep_fsm_states,
 | 
						.states = osmo_mgcpc_ep_fsm_states,
 | 
				
			||||||
@@ -986,5 +1032,5 @@ static struct osmo_fsm osmo_mgcpc_ep_fsm = {
 | 
				
			|||||||
	.log_subsys = DLMGCP,
 | 
						.log_subsys = DLMGCP,
 | 
				
			||||||
	.event_names = osmo_mgcpc_ep_fsm_event_names,
 | 
						.event_names = osmo_mgcpc_ep_fsm_event_names,
 | 
				
			||||||
	.timer_cb = osmo_mgcpc_ep_fsm_timer_cb,
 | 
						.timer_cb = osmo_mgcpc_ep_fsm_timer_cb,
 | 
				
			||||||
	/* The FSM termination will automatically trigger any mgcp_client_fsm instances to DLCX. */
 | 
						.pre_term = osmo_mgcpc_ep_fsm_pre_term,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -252,6 +252,18 @@ const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	return mgcp_ctx->conn_id;
 | 
						return mgcp_ctx->conn_id;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the mgcp_client that is used with this mgcp_client_fsm instance */
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_ctx *mgcp_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!fi)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_ctx = fi->priv;
 | 
				
			||||||
 | 
						return mgcp_ctx->mgcp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
 | 
					static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_fsm_inst *fi = priv;
 | 
						struct osmo_fsm_inst *fi = priv;
 | 
				
			||||||
@@ -521,10 +533,12 @@ static void fsm_cleanup_cb(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause ca
 | 
				
			|||||||
	/* Should the FSM be terminated while there are still open connections
 | 
						/* Should the FSM be terminated while there are still open connections
 | 
				
			||||||
	 * on the MGW, we send an unconditional DLCX to terminate the
 | 
						 * on the MGW, we send an unconditional DLCX to terminate the
 | 
				
			||||||
	 * connection. This is not the normal case. The user should always use
 | 
						 * connection. This is not the normal case. The user should always use
 | 
				
			||||||
	 * mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
 | 
						 * mgcp_conn_delete() to instruct the FSM to perform a graceful exit.
 | 
				
			||||||
	if (strlen(mgcp_ctx->conn_id)) {
 | 
						 * If in ST_DLCX_RESP, a DLCX was already sent and we did not get a
 | 
				
			||||||
		LOGPFSML(fi, LOGL_NOTICE,
 | 
						 * response. No point in sending another one. */
 | 
				
			||||||
			 "MGW/DLCX: FSM termination with connections still present, sending unconditional DLCX...\n");
 | 
						if (fi->state != ST_DLCX_RESP && strlen(mgcp_ctx->conn_id)) {
 | 
				
			||||||
 | 
							LOGPFSML(fi, LOGL_INFO, "Conn cleanup, sending DLCX for %s %s\n", mgcp_ctx->conn_peer_remote.endpoint,
 | 
				
			||||||
 | 
								 mgcp_ctx->conn_id);
 | 
				
			||||||
		msg = make_dlcx_msg(mgcp_ctx);
 | 
							msg = make_dlcx_msg(mgcp_ctx);
 | 
				
			||||||
		if (!msg)
 | 
							if (!msg)
 | 
				
			||||||
			LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
 | 
								LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
 | 
				
			||||||
@@ -594,6 +608,7 @@ static struct osmo_fsm fsm_mgcp_client = {
 | 
				
			|||||||
	.timer_cb = fsm_timeout_cb,
 | 
						.timer_cb = fsm_timeout_cb,
 | 
				
			||||||
	.cleanup = fsm_cleanup_cb,
 | 
						.cleanup = fsm_cleanup_cb,
 | 
				
			||||||
	.event_names = fsm_mgcp_client_evt_names,
 | 
						.event_names = fsm_mgcp_client_evt_names,
 | 
				
			||||||
 | 
						.log_subsys = DLMGCP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate FSM, and create a new connection on the MGW.
 | 
					/*! allocate FSM, and create a new connection on the MGW.
 | 
				
			||||||
@@ -707,8 +722,8 @@ void mgcp_conn_delete(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	if (fi->proc.terminating)
 | 
						if (fi->proc.terminating)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Unlink FSM from parent */
 | 
						/* Unlink FSM from parent, set the struct mgcp_client as new talloc ctx. */
 | 
				
			||||||
	osmo_fsm_inst_unlink_parent(fi, NULL);
 | 
						osmo_fsm_inst_unlink_parent(fi, mgcp_ctx->mgcp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* An error situation where the parent FSM must be killed immediately
 | 
						/* An error situation where the parent FSM must be killed immediately
 | 
				
			||||||
	 * may lead into a situation where the DLCX can not be executed right
 | 
						 * may lead into a situation where the DLCX can not be executed right
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										216
									
								
								src/libosmo-mgcp-client/mgcp_client_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/libosmo-mgcp-client/mgcp_client_pool.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Philipp Maier
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPPMGW(pool_member, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get a human readable name for a given pool member. */
 | 
				
			||||||
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_client *mpcp_client;
 | 
				
			||||||
 | 
						struct mgcp_client mpcp_client_dummy;
 | 
				
			||||||
 | 
						static char name[512];
 | 
				
			||||||
 | 
						const char *description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pool_member)
 | 
				
			||||||
 | 
							return "(null)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
 | 
				
			||||||
 | 
						 * initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
 | 
				
			||||||
 | 
							mpcp_client = &mpcp_client_dummy;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mpcp_client = pool_member->client;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						description = mgcp_client_name(mpcp_client);
 | 
				
			||||||
 | 
						snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
 | 
				
			||||||
 | 
					 *  mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
 | 
				
			||||||
 | 
					 *  \param[in] talloc_ctx talloc context. */
 | 
				
			||||||
 | 
					struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool = talloc_zero(talloc_ctx, struct mgcp_client_pool);
 | 
				
			||||||
 | 
						if (!pool)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&pool->pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pool;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Initialize and connect an mcgp client pool.
 | 
				
			||||||
 | 
					 *  \param[in,out] mgcp MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns number of successfully initialized pool members. */
 | 
				
			||||||
 | 
					unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						unsigned int pool_members_initialized = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Initialize client */
 | 
				
			||||||
 | 
							pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
				
			||||||
 | 
							if (!pool_member->client) {
 | 
				
			||||||
 | 
								LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Set backpointer so that we can detect later that this MGCP client is managed
 | 
				
			||||||
 | 
							 * by this pool. */
 | 
				
			||||||
 | 
							pool_member->client->pool = pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Connect client */
 | 
				
			||||||
 | 
							if (mgcp_client_connect2(pool_member->client, 0)) {
 | 
				
			||||||
 | 
								LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
 | 
				
			||||||
 | 
									 pool_member->conf.remote_addr, pool_member->conf.remote_port);
 | 
				
			||||||
 | 
								talloc_free(pool_member->client);
 | 
				
			||||||
 | 
								pool_member->client = NULL;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pool_members_initialized++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pool_members_initialized;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! register a single mgcp_client instance to the pool.
 | 
				
			||||||
 | 
					 *  \param[out] pool MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] mgcp MGCP client descriptor. */
 | 
				
			||||||
 | 
					void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*! Some applications still support the non-pooled MGW VTY configuration variant provided by
 | 
				
			||||||
 | 
						 *  mgcp_client_vty_init(). If this is the case the mgcp_client instance created by mgcp_client_init()
 | 
				
			||||||
 | 
						 *  can be registered here so that it will appear as if it were part of the pool. When the user actively
 | 
				
			||||||
 | 
						 *  configures MGW pool members, the MGCP client registered here will be ignored. (The registration of
 | 
				
			||||||
 | 
						 *  multiple singe mgcp_client instances is not possible.) */
 | 
				
			||||||
 | 
						pool->mgcp_client_single = mgcp_client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
				
			||||||
 | 
					 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
				
			||||||
 | 
					static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member_picked = NULL;
 | 
				
			||||||
 | 
						unsigned int n_pool_members = llist_count(&pool->pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
							if (pool_member->blocked == false && pool_member->client) {
 | 
				
			||||||
 | 
								if (!pool_member_picked)
 | 
				
			||||||
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
 | 
								else if (pool_member_picked->refcount > pool_member->refcount)
 | 
				
			||||||
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
 | 
				
			||||||
 | 
									 pool_member->nr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pool_member_picked) {
 | 
				
			||||||
 | 
							LOGPPMGW(pool_member_picked, LOGL_DEBUG, "MGW pool has %u members -- using MGW %u (active calls: %u)\n",
 | 
				
			||||||
 | 
								 n_pool_members, pool_member_picked->nr, pool_member_picked->refcount);
 | 
				
			||||||
 | 
							return pool_member_picked;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
						     "MGW pool has %u members, but no functional MGW pool member found -- check configuration!\n",
 | 
				
			||||||
 | 
						     n_pool_members);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! get an MGCP client from the pool (increment reference counter).
 | 
				
			||||||
 | 
					 *  \param[in,out] pool MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns MGCP client descriptor, NULL if no member was found (empty pool). */
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! When an MGCP client is taken from the pool it is still available for other calls. In fact only a reference
 | 
				
			||||||
 | 
						 *  counter is incremented to keep track on how many references to a specific MGCP client are currently used
 | 
				
			||||||
 | 
						 *  by the application code. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When the pool is empty, return a single MGCP client if it is registered. */
 | 
				
			||||||
 | 
						if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
 | 
				
			||||||
 | 
							     mgcp_client_name(pool->mgcp_client_single));
 | 
				
			||||||
 | 
							return pool->mgcp_client_single;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Abort when the pool is empty */
 | 
				
			||||||
 | 
						if (llist_empty(&pool->pool)) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Pick a suitable pool member */
 | 
				
			||||||
 | 
						pool_member = mgcp_client_pool_pick(pool);
 | 
				
			||||||
 | 
						if (pool_member) {
 | 
				
			||||||
 | 
							pool_member->refcount++;
 | 
				
			||||||
 | 
							return pool_member->client;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! put an MGCP client back into the pool (decrement reference counter).
 | 
				
			||||||
 | 
					 *  \param[in,out] pool MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function is able to detect automatically to which pool the mgcp_client belongs. If the mgcp_client does
 | 
				
			||||||
 | 
					 * not belong to a pool at all, the function call will have no effect. */
 | 
				
			||||||
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_client)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_client->pool)
 | 
				
			||||||
 | 
							pool = mgcp_client->pool;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
							if (pool_member->client == mgcp_client) {
 | 
				
			||||||
 | 
								if (pool_member->refcount == 0) {
 | 
				
			||||||
 | 
									LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pool_member->refcount--;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,16 +24,36 @@
 | 
				
			|||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <talloc.h>
 | 
					#include <talloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/vty/vty.h>
 | 
				
			||||||
#include <osmocom/vty/command.h>
 | 
					#include <osmocom/vty/command.h>
 | 
				
			||||||
#include <osmocom/vty/misc.h>
 | 
					#include <osmocom/vty/misc.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/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_pool_internal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
					#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *global_mgcp_client_ctx = NULL;
 | 
					/* Only common (non-pooled) VTY connands will use this talloc context. All
 | 
				
			||||||
struct mgcp_client_conf *global_mgcp_client_conf = NULL;
 | 
					 * pooled VTY commands will use the pool (global_mgcp_client_pool) as
 | 
				
			||||||
 | 
					 * talloc context. */
 | 
				
			||||||
 | 
					static void *global_mgcp_client_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MGCP Client configuration used with mgcp_client_vty_init(). (This pointer
 | 
				
			||||||
 | 
					 * points to user provided memory, so it cannot be used as talloc context.) */
 | 
				
			||||||
 | 
					static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
					static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
				
			||||||
 | 
							return vty->index;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return global_mgcp_client_conf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "mgw local-ip " VTY_IPV46_CMD,
 | 
					      "mgw local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
@@ -41,11 +61,10 @@ DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			|||||||
      "local bind IPv4 address\n"
 | 
					      "local bind IPv4 address\n"
 | 
				
			||||||
      "local bind IPv6 address\n")
 | 
					      "local bind IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(global_mgcp_client_ctx);
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(global_mgcp_client_ctx,
 | 
						osmo_talloc_replace_string(global_mgcp_client_ctx,
 | 
				
			||||||
				   (char**)&global_mgcp_client_conf->local_addr,
 | 
									   (char **)&conf->local_addr,
 | 
				
			||||||
				   argv[0]);
 | 
									   argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -59,9 +78,9 @@ DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
				
			|||||||
      MGW_STR "local port to connect to MGW from\n"
 | 
					      MGW_STR "local port to connect to MGW from\n"
 | 
				
			||||||
      "local bind port\n")
 | 
					      "local bind port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
					
 | 
				
			||||||
	global_mgcp_client_conf->local_port = atoi(argv[0]);
 | 
						conf->local_port = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
 | 
				
			||||||
@@ -75,12 +94,10 @@ DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
				
			|||||||
      "remote IPv4 address\n"
 | 
					      "remote IPv4 address\n"
 | 
				
			||||||
      "remote IPv6 address\n")
 | 
					      "remote IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(global_mgcp_client_ctx);
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(global_mgcp_client_ctx,
 | 
						osmo_talloc_replace_string(global_mgcp_client_ctx,
 | 
				
			||||||
				   (char**)&global_mgcp_client_conf->remote_addr,
 | 
									   (char **)&conf->remote_addr, argv[0]);
 | 
				
			||||||
				   argv[0]);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
 | 
				
			||||||
@@ -93,9 +110,9 @@ DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
				
			|||||||
      MGW_STR "remote port to reach the MGW at\n"
 | 
					      MGW_STR "remote port to reach the MGW at\n"
 | 
				
			||||||
      "remote port\n")
 | 
					      "remote port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
					
 | 
				
			||||||
	global_mgcp_client_conf->remote_port = atoi(argv[0]);
 | 
						conf->remote_port = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
 | 
				
			||||||
@@ -145,50 +162,129 @@ DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			|||||||
      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
					      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
				
			||||||
      "Domain name, should be alphanumeric.\n")
 | 
					      "Domain name, should be alphanumeric.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (osmo_strlcpy(global_mgcp_client_conf->endpoint_domain_name, argv[0],
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
			 sizeof(global_mgcp_client_conf->endpoint_domain_name))
 | 
					
 | 
				
			||||||
	    >= sizeof(global_mgcp_client_conf->endpoint_domain_name)) {
 | 
						if (osmo_strlcpy(conf->endpoint_domain_name, argv[0], sizeof(conf->endpoint_domain_name))
 | 
				
			||||||
 | 
						    >= sizeof(conf->endpoint_domain_name)) {
 | 
				
			||||||
		vty_out(vty, "%% Error: 'mgw endpoint-domain' name too long, max length is %zu: '%s'%s",
 | 
							vty_out(vty, "%% Error: 'mgw endpoint-domain' name too long, max length is %zu: '%s'%s",
 | 
				
			||||||
			sizeof(global_mgcp_client_conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);
 | 
								sizeof(conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
					DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "mgw reset-endpoint NAME",
 | 
				
			||||||
 | 
					      MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
				
			||||||
 | 
					      "e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *addr;
 | 
						int rc;
 | 
				
			||||||
	int port;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = global_mgcp_client_conf->local_addr;
 | 
						/* stop when the address is already in the list */
 | 
				
			||||||
	if (addr)
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
 | 
				
			||||||
		vty_out(vty, "%smgw local-ip %s%s", indent, addr,
 | 
							if (strcmp(argv[0], reset_ep->name) == 0) {
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
	port = global_mgcp_client_conf->local_port;
 | 
								return CMD_WARNING;
 | 
				
			||||||
	if (port >= 0)
 | 
							}
 | 
				
			||||||
		vty_out(vty, "%smgw local-port %u%s", indent,
 | 
						}
 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = global_mgcp_client_conf->remote_addr;
 | 
						/* the domain name is not part of the actual endpoint name */
 | 
				
			||||||
	if (addr)
 | 
						if (strchr(argv[0], '@')) {
 | 
				
			||||||
		vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
 | 
							vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								argv[0], VTY_NEWLINE);
 | 
				
			||||||
	port = global_mgcp_client_conf->remote_port;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	if (port >= 0)
 | 
						}
 | 
				
			||||||
		vty_out(vty, "%smgw remote-port %u%s", indent,
 | 
					 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (global_mgcp_client_conf->endpoint_domain_name[0])
 | 
						reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);
 | 
				
			||||||
		vty_out(vty, "%smgw endpoint-domain %s%s", indent,
 | 
						OSMO_ASSERT(reset_ep);
 | 
				
			||||||
			global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_strlcpy(reset_ep->name, argv[0], sizeof(reset_ep->name));
 | 
				
			||||||
 | 
						if (rc >= sizeof(reset_ep->name)) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% Error: 'mgw reset-endpoint' name too long, max length is %zu: '%s'%s",
 | 
				
			||||||
 | 
								sizeof(reset_ep->name) - 1, argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							talloc_free(reset_ep);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_add_tail(&reset_ep->list, &conf->reset_epnames);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
 | 
					DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_no_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "no mgw reset-endpoint NAME",
 | 
				
			||||||
 | 
					      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
 | 
				
			||||||
 | 
							if (strcmp(argv[0], reset_ep->name) == 0) {
 | 
				
			||||||
 | 
								llist_del(&reset_ep->list);
 | 
				
			||||||
 | 
								talloc_free(reset_ep);
 | 
				
			||||||
 | 
								return CMD_SUCCESS;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
						return CMD_WARNING;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *addr;
 | 
				
			||||||
 | 
						int port;
 | 
				
			||||||
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->description)
 | 
				
			||||||
 | 
							vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = conf->local_addr;
 | 
				
			||||||
 | 
						if (addr)
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw local-ip %s%s", indent, addr,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
						port = conf->local_port;
 | 
				
			||||||
 | 
						if (port >= 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw local-port %u%s", indent,
 | 
				
			||||||
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = conf->remote_addr;
 | 
				
			||||||
 | 
						if (addr)
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
						port = conf->remote_port;
 | 
				
			||||||
 | 
						if (port >= 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw remote-port %u%s", indent,
 | 
				
			||||||
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->endpoint_domain_name[0])
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw endpoint-domain %s%s", indent,
 | 
				
			||||||
 | 
								conf->endpoint_domain_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Write out MGCP client config to VTY.
 | 
				
			||||||
 | 
					 *  \param[in] vty VTY to which we should print.
 | 
				
			||||||
 | 
					 *  \param[in] string used for indentation (e.g. " ").
 | 
				
			||||||
 | 
					 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
				
			||||||
 | 
					int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return config_write(vty, indent, global_mgcp_client_conf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vty_init_common(void *talloc_ctx, int node)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	global_mgcp_client_ctx = talloc_ctx;
 | 
						global_mgcp_client_ctx = talloc_ctx;
 | 
				
			||||||
	global_mgcp_client_conf = conf;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_local_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_local_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
				
			||||||
@@ -197,6 +293,20 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
 | 
				
			|||||||
	install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Set up MGCP client VTY
 | 
				
			||||||
 | 
					 *  (called once at startup by the application process).
 | 
				
			||||||
 | 
					 *  \param[in] talloc_ctx talloc context to be used by the VTY for allocating memory.
 | 
				
			||||||
 | 
					 *  \param[in] node identifier of the node on which the VTY commands should be installed.
 | 
				
			||||||
 | 
					 *  \param[in] conf user provided memory to to store the MGCP client configuration data. */
 | 
				
			||||||
 | 
					void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						global_mgcp_client_conf = conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* deprecated 'mgcpgw' commands */
 | 
						/* deprecated 'mgcpgw' commands */
 | 
				
			||||||
	install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
 | 
				
			||||||
@@ -206,5 +316,242 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
 | 
				
			|||||||
	install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fsm_vty_add_cmds();
 | 
						vty_init_common(talloc_ctx, node);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int config_write_pool(struct vty *vty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
 | 
				
			||||||
 | 
						char *indent = talloc_zero_size(vty, indent_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
 | 
				
			||||||
 | 
							config_write(vty, indent, &pool_member->conf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(indent);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Lookup the selected MGCP client config by its reference number */
 | 
				
			||||||
 | 
					static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member_tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
 | 
				
			||||||
 | 
							if (pool_member_tmp->nr == nr) {
 | 
				
			||||||
 | 
								pool_member = pool_member_tmp;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pool_member;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_ATTR(cfg_mgw,
 | 
				
			||||||
 | 
						   cfg_mgw_cmd, "mgw <0-255>", "Select a MGCP client config to setup\n" "reference number\n", CMD_ATTR_IMMEDIATE)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
 | 
				
			||||||
 | 
							OSMO_ASSERT(pool_member);
 | 
				
			||||||
 | 
							mgcp_client_conf_init(&pool_member->conf);
 | 
				
			||||||
 | 
							pool_member->nr = nr;
 | 
				
			||||||
 | 
							llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty->index = &pool_member->conf;
 | 
				
			||||||
 | 
						vty->index_sub = &pool_member->conf.description;
 | 
				
			||||||
 | 
						vty->node = global_mgcp_client_pool->vty_node->node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_ATTR(cfg_no_mgw,
 | 
				
			||||||
 | 
						   cfg_no_mgw_cmd,
 | 
				
			||||||
 | 
						   "no mgw <0-255>", NO_STR "Select a MGCP client config to remove\n" "reference number\n", CMD_ATTR_IMMEDIATE)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure that there are no ongoing calls */
 | 
				
			||||||
 | 
						if (pool_member->refcount > 0) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't remove it now!%s",
 | 
				
			||||||
 | 
								mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_del(&pool_member->list);
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						talloc_free(pool_member);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
 | 
				
			||||||
 | 
						   "mgw <0-255> reconnect",
 | 
				
			||||||
 | 
						   MGW_STR "reference number\n" "reconfigure and reconnect MGCP client\n", CMD_ATTR_IMMEDIATE)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure that there are no ongoing calls */
 | 
				
			||||||
 | 
						if (pool_member->refcount > 0) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't reconnect it now!%s",
 | 
				
			||||||
 | 
								mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get rid of a possibly existing old MGCP client instance first */
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a new MGCP client instance with the current config */
 | 
				
			||||||
 | 
						pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
 | 
				
			||||||
 | 
							     mgcp_client_pool_member_name(pool_member));
 | 
				
			||||||
 | 
							vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
				
			||||||
 | 
								mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
				
			||||||
 | 
						pool_member->client->pool = global_mgcp_client_pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Connect client */
 | 
				
			||||||
 | 
						if (mgcp_client_connect(pool_member->client)) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
 | 
				
			||||||
 | 
							     mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
 | 
				
			||||||
 | 
							     pool_member->conf.remote_port);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
							pool_member->client = NULL;
 | 
				
			||||||
 | 
							vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
				
			||||||
 | 
								mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_ATTR(mgw_block, mgw_block_cmd,
 | 
				
			||||||
 | 
						   "mgw <0-255> block",
 | 
				
			||||||
 | 
						   MGW_STR "reference number\n" "block MGCP client so that it won't be used for new calls\n", CMD_ATTR_IMMEDIATE)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member->blocked = true;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
 | 
				
			||||||
 | 
						   "mgw <0-255> unblock",
 | 
				
			||||||
 | 
						   MGW_STR "reference number\n" "unblock MGCP client so that it will be available for new calls\n", CMD_ATTR_IMMEDIATE)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member->blocked = false;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
 | 
				
			||||||
 | 
							vty_out(vty, "%%  (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
						} else if (llist_empty(&global_mgcp_client_pool->pool)) {
 | 
				
			||||||
 | 
							vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
 | 
				
			||||||
 | 
							vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "%%   service:       %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "%%   ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Set up MGCP client VTY (pooled)
 | 
				
			||||||
 | 
					 *  (called once at startup by the application process).
 | 
				
			||||||
 | 
					 *  \param[in] parent_node identifier of the parent node on which the mgw node appears.
 | 
				
			||||||
 | 
					 *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.
 | 
				
			||||||
 | 
					 *  \param[in] indent indentation string to match the indentation in the VTY config
 | 
				
			||||||
 | 
					 *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
 | 
				
			||||||
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* A pool must be allocated before this function can be called */
 | 
				
			||||||
 | 
						OSMO_ASSERT(pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Never allow this function to be called twice on the same pool */
 | 
				
			||||||
 | 
						OSMO_ASSERT(!pool->vty_indent);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!pool->vty_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool->vty_indent = talloc_strdup(pool, indent);
 | 
				
			||||||
 | 
						OSMO_ASSERT(pool->vty_indent);
 | 
				
			||||||
 | 
						pool->vty_node = talloc_zero(pool, struct cmd_node);
 | 
				
			||||||
 | 
						OSMO_ASSERT(pool->vty_node);
 | 
				
			||||||
 | 
						pool->vty_node->node = mgw_node;
 | 
				
			||||||
 | 
						pool->vty_node->vtysh = 1;
 | 
				
			||||||
 | 
						pool->vty_node->prompt = talloc_strdup(pool->vty_node, "%s(config-mgw)# ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_lib_element(parent_node, &cfg_mgw_cmd);
 | 
				
			||||||
 | 
						install_lib_element(parent_node, &cfg_no_mgw_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_node(pool->vty_node, config_write_pool);
 | 
				
			||||||
 | 
						vty_init_common(pool, mgw_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_element(mgw_node, &cfg_description_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_lib_element(ENABLE_NODE, &mgw_reconnect_cmd);
 | 
				
			||||||
 | 
						install_lib_element(ENABLE_NODE, &mgw_block_cmd);
 | 
				
			||||||
 | 
						install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						install_lib_element_ve(&mgw_snow_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						global_mgcp_client_pool = pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,4 +48,5 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_ctrl.c \
 | 
						mgcp_ctrl.c \
 | 
				
			||||||
	mgcp_ratectr.c \
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
	mgcp_e1.c \
 | 
						mgcp_e1.c \
 | 
				
			||||||
 | 
						mgcp_iuup.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,10 +14,6 @@
 | 
				
			|||||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 *  GNU General Public License for more details.
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 *  along with this program; if not, write to the Free Software
 | 
					 | 
				
			||||||
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int val_seg(int val)
 | 
					static inline int val_seg(int val)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,15 +89,13 @@ static void codec_init(struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
		.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN,
 | 
							.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN,
 | 
				
			||||||
		.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE,
 | 
							.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE,
 | 
				
			||||||
		.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS,
 | 
							.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS,
 | 
				
			||||||
 | 
							.subtype_name = "",
 | 
				
			||||||
 | 
							.audio_name = "",
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void codec_free(struct mgcp_rtp_codec *codec)
 | 
					static void codec_free(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (codec->subtype_name)
 | 
					 | 
				
			||||||
		talloc_free(codec->subtype_name);
 | 
					 | 
				
			||||||
	if (codec->audio_name)
 | 
					 | 
				
			||||||
		talloc_free(codec->audio_name);
 | 
					 | 
				
			||||||
	*codec = (struct mgcp_rtp_codec){};
 | 
						*codec = (struct mgcp_rtp_codec){};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,10 +122,8 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int rate;
 | 
						int rate;
 | 
				
			||||||
	int channels;
 | 
						int channels;
 | 
				
			||||||
	char audio_codec[64];
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	unsigned int pt_offset = conn->end.codecs_assigned;
 | 
						unsigned int pt_offset = conn->end.codecs_assigned;
 | 
				
			||||||
	void *ctx = conn->conn;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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. */
 | 
				
			||||||
@@ -160,16 +156,16 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
				
			|||||||
	if (!audio_name) {
 | 
						if (!audio_name) {
 | 
				
			||||||
		switch (payload_type) {
 | 
							switch (payload_type) {
 | 
				
			||||||
		case 0:
 | 
							case 0:
 | 
				
			||||||
			audio_name = talloc_strdup(ctx, "PCMU/8000/1");
 | 
								strcpy(codec->audio_name, "PCMU/8000/1");
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 3:
 | 
							case 3:
 | 
				
			||||||
			audio_name = talloc_strdup(ctx, "GSM/8000/1");
 | 
								strcpy(codec->audio_name, "GSM/8000/1");
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 8:
 | 
							case 8:
 | 
				
			||||||
			audio_name = talloc_strdup(ctx, "PCMA/8000/1");
 | 
								strcpy(codec->audio_name, "PCMA/8000/1");
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 18:
 | 
							case 18:
 | 
				
			||||||
			audio_name = talloc_strdup(ctx, "G729/8000/1");
 | 
								strcpy(codec->audio_name, "G729/8000/1");
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* The given payload type is not known to us, or it
 | 
								/* The given payload type is not known to us, or it
 | 
				
			||||||
@@ -179,36 +175,36 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
				
			|||||||
			     payload_type);
 | 
								     payload_type);
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							OSMO_STRLCPY_ARRAY(codec->audio_name, audio_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Now we extract the codec subtype name, rate and channels. The latter
 | 
						/* Now we extract the codec subtype name, rate and channels. The latter
 | 
				
			||||||
	 * two are optional. If they are not present we use the safe defaults
 | 
						 * two are optional. If they are not present we use the safe defaults
 | 
				
			||||||
	 * above. */
 | 
						 * above. */
 | 
				
			||||||
	if (strlen(audio_name) >= sizeof(audio_codec)) {
 | 
						if (strlen(codec->audio_name) >= sizeof(codec->subtype_name)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(audio_name, -1));
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(codec->audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
 | 
						channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
 | 
				
			||||||
	rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
 | 
						rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
 | 
				
			||||||
	if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1) {
 | 
						if (sscanf(codec->audio_name, "%63[^/]/%d/%d", codec->subtype_name, &rate, &channels) < 1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(audio_name, -1));
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(codec->audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: We only accept configurations with one audio channel! */
 | 
						/* Note: We only accept configurations with one audio channel! */
 | 
				
			||||||
	if (channels != 1) {
 | 
						if (channels != 1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot handle audio codec with more than one channel: %s\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Cannot handle audio codec with more than one channel: %s\n",
 | 
				
			||||||
		     osmo_quote_str(audio_name, -1));
 | 
							     osmo_quote_str(codec->audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	codec->rate = rate;
 | 
						codec->rate = rate;
 | 
				
			||||||
	codec->channels = channels;
 | 
						codec->channels = channels;
 | 
				
			||||||
	codec->subtype_name = talloc_strdup(ctx, audio_codec);
 | 
					 | 
				
			||||||
	codec->audio_name = talloc_strdup(ctx, audio_name);
 | 
					 | 
				
			||||||
	codec->payload_type = payload_type;
 | 
						codec->payload_type = payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strcmp(audio_codec, "G729")) {
 | 
						if (!strcmp(codec->subtype_name, "G729")) {
 | 
				
			||||||
		codec->frame_duration_num = 10;
 | 
							codec->frame_duration_num = 10;
 | 
				
			||||||
		codec->frame_duration_den = 1000;
 | 
							codec->frame_duration_den = 1000;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -287,7 +283,7 @@ static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct m
 | 
				
			|||||||
	/* A codec name must be set, if not, this might mean that the codec
 | 
						/* A codec name must be set, if not, this might mean that the codec
 | 
				
			||||||
	 * (payload type) that was assigned is unknown to us so we must stop
 | 
						 * (payload type) that was assigned is unknown to us so we must stop
 | 
				
			||||||
	 * here. */
 | 
						 * here. */
 | 
				
			||||||
	if (!codec->subtype_name)
 | 
						if (!strlen(codec->subtype_name))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: implement meaningful checks to make sure that the given codec
 | 
						/* FIXME: implement meaningful checks to make sure that the given codec
 | 
				
			||||||
@@ -359,7 +355,7 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * https://tools.ietf.org/html/rfc4867
 | 
					 * https://tools.ietf.org/html/rfc4867
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
					bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!codec->param_present)
 | 
						if (!codec->param_present)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -382,10 +378,10 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
						if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (!strcmp(codec_a->subtype_name, "AMR")) {
 | 
					
 | 
				
			||||||
		if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
 | 
						/* Note: AMR allows to set the RTP payload format to octet-aligned or bandwith-efficient (octet-aligned=0)
 | 
				
			||||||
			return false;
 | 
						 * via SDP. This difference concerns payload format only, but not the actual codec. It is not a difference
 | 
				
			||||||
	}
 | 
						 * within the meaning of this function. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -421,7 +417,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
	if (!codec_src)
 | 
						if (!codec_src)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Use the codec infrmation from the source and try to find the
 | 
						/* Use the codec information from the source and try to find the
 | 
				
			||||||
	 * equivalent of it on the destination side */
 | 
						 * equivalent of it on the destination side */
 | 
				
			||||||
	codecs_assigned = rtp_dst->codecs_assigned;
 | 
						codecs_assigned = rtp_dst->codecs_assigned;
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdatomic.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_protocol.h>
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
@@ -29,6 +30,8 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_iuup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/gsm/gsm_utils.h>
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
@@ -89,7 +92,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	/* 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. */
 | 
				
			||||||
	static unsigned int rate_ctr_index = 0;
 | 
						static atomic_uint rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
						conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
				
			||||||
	conn_rtp->osmux.cid_allocated = false;
 | 
						conn_rtp->osmux.cid_allocated = false;
 | 
				
			||||||
@@ -107,16 +110,15 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	/* Set default values */
 | 
						/* Set default values */
 | 
				
			||||||
	end->frames_per_packet = 0;	/* unknown */
 | 
						end->frames_per_packet = 0;	/* unknown */
 | 
				
			||||||
	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
						end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
				
			||||||
	end->output_enabled = 0;
 | 
						end->output_enabled = false;
 | 
				
			||||||
	end->maximum_packet_time = -1;
 | 
						end->maximum_packet_time = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);
 | 
						conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
				
			||||||
	if (!conn_rtp->rate_ctr_group)
 | 
						if (!conn_rtp->rate_ctr_group)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];
 | 
						conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];
 | 
						conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	rate_ctr_index++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
@@ -129,6 +131,8 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
						if (mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
				
			||||||
		conn_osmux_disable(conn_rtp);
 | 
							conn_osmux_disable(conn_rtp);
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
				
			||||||
 | 
							mgcp_conn_iuup_cleanup(conn_rtp);
 | 
				
			||||||
	mgcp_free_rtp_port(&conn_rtp->end);
 | 
						mgcp_free_rtp_port(&conn_rtp->end);
 | 
				
			||||||
	rate_ctr_group_free(conn_rtp->rate_ctr_group);
 | 
						rate_ctr_group_free(conn_rtp->rate_ctr_group);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
@@ -143,7 +147,7 @@ void mgcp_conn_watchdog_cb(void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int timeout = conn->endp->cfg->conn_timeout;
 | 
						int timeout = conn->endp->trunk->cfg->conn_timeout;
 | 
				
			||||||
	if (!timeout)
 | 
						if (!timeout)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -270,12 +274,12 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
 | 
				
			|||||||
	OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
 | 
						OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* all other counters are [now] updated in real-time */
 | 
						/* all other counters are [now] updated in real-time */
 | 
				
			||||||
	rate_ctr_add(&all_stats->ctr[IN_STREAM_ERR_TSTMP_CTR],
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(all_stats, IN_STREAM_ERR_TSTMP_CTR),
 | 
				
			||||||
		     conn_stats->ctr[IN_STREAM_ERR_TSTMP_CTR].current);
 | 
							     rate_ctr_group_get_ctr(conn_stats, IN_STREAM_ERR_TSTMP_CTR)->current);
 | 
				
			||||||
	rate_ctr_add(&all_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR],
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(all_stats, OUT_STREAM_ERR_TSTMP_CTR),
 | 
				
			||||||
		     conn_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR].current);
 | 
							     rate_ctr_group_get_ctr(conn_stats, OUT_STREAM_ERR_TSTMP_CTR)->current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_inc(&all_stats->ctr[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 by its ID.
 | 
				
			||||||
@@ -325,15 +329,18 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! free all connections at once.
 | 
					/*! free all connections at once.
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 *  \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)
 | 
					void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
	struct mgcp_conn *conn_tmp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Drop all items in the list */
 | 
						/* Drop all items in the list, might be consecutive! */
 | 
				
			||||||
	llist_for_each_entry_safe(conn, conn_tmp, &endp->conns, entry) {
 | 
						while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
				
			||||||
		mgcp_conn_free(endp, conn->id);
 | 
							mgcp_conn_free(endp, conn->id);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -192,12 +192,12 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint *endp = user_data;
 | 
						struct mgcp_endpoint *endp = user_data;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
	struct msgb *msg = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
 | 
						struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
 | 
				
			||||||
	uint8_t *ptr;
 | 
						uint8_t *ptr;
 | 
				
			||||||
	const uint8_t *ptr_ft;
 | 
						const uint8_t *ptr_ft;
 | 
				
			||||||
	enum osmo_trau_frame_type ft;
 | 
						enum osmo_trau_frame_type ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_MUX_EMPTY_CTR]);
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Choose an appropiate idle frame type */
 | 
						/* Choose an appropiate idle frame type */
 | 
				
			||||||
	ft = endp->e1.trau_rtp_st->type;
 | 
						ft = endp->e1.trau_rtp_st->type;
 | 
				
			||||||
@@ -238,9 +238,9 @@ static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_da
 | 
				
			|||||||
 * (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */
 | 
					 * (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */
 | 
				
			||||||
static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)
 | 
					static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx-from-E1");
 | 
					 | 
				
			||||||
	unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
						unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
				
			||||||
	struct mgcp_endpoint *endp = user_data;
 | 
						struct mgcp_endpoint *endp = user_data;
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx-from-E1");
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
	struct osmo_trau_frame fr;
 | 
						struct osmo_trau_frame fr;
 | 
				
			||||||
@@ -304,7 +304,7 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
 | 
				
			|||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
skip:
 | 
					skip:
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_RX_FAIL_CTR]);
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -312,7 +312,7 @@ skip:
 | 
				
			|||||||
/* Function to handle outgoing E1 traffic */
 | 
					/* Function to handle outgoing E1 traffic */
 | 
				
			||||||
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
					static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = msgb_alloc(E1_TS_BYTES, "E1-TX-timeslot-bytes");
 | 
						struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
 | 
				
			||||||
	uint8_t *ptr;
 | 
						uint8_t *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Get E1 frame from I.460 multiplexer */
 | 
						/* Get E1 frame from I.460 multiplexer */
 | 
				
			||||||
@@ -337,7 +337,8 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
	/* Find associated trunk */
 | 
						/* Find associated trunk */
 | 
				
			||||||
	trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
 | 
						trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
 | 
				
			||||||
	if (!trunk) {
 | 
						if (!trunk) {
 | 
				
			||||||
		LOGP(DE1, LOGL_DEBUG, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
 | 
							LOGP(DE1, LOGL_ERROR, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,6 +360,9 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Trigger sending of pending E1 traffic */
 | 
						/* Trigger sending of pending E1 traffic */
 | 
				
			||||||
	e1_send(ts, trunk);
 | 
						e1_send(ts, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* e1inp_rx_ts() does not free() msgb */
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
					static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
@@ -376,14 +380,14 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
	cfg = trunk->cfg;
 | 
						cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trunk->e1.ts_in_use[ts_nr - 1]) {
 | 
						if (trunk->e1.ts_in_use[ts_nr - 1]) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u already set up, skipping...\n", ts_nr);
 | 
							LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Get E1 line */
 | 
						/* Get E1 line */
 | 
				
			||||||
	e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
						e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
				
			||||||
	if (!e1_line) {
 | 
						if (!e1_line) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "no such E1 line %u - check VTY config!\n",
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
 | 
				
			||||||
			  trunk->e1.vty_line_nr);
 | 
								  trunk->e1.vty_line_nr);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -401,7 +405,7 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u set up successfully.\n", ts_nr);
 | 
						LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
 | 
				
			||||||
	trunk->e1.ts_in_use[ts_nr - 1] = true;
 | 
						trunk->e1.ts_in_use[ts_nr - 1] = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -545,7 +549,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
				
			|||||||
	endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;
 | 
						endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;
 | 
				
			||||||
	endp->e1.scd.mux.user_data = endp;
 | 
						endp->e1.scd.mux.user_data = endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DE1, LOGL_DEBUG, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
 | 
						LOGPENDP(endp, DE1, LOGL_INFO, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
 | 
				
			||||||
		 offs, e1_rates[ss], endp->e1.scd.demux.num_bits);
 | 
							 offs, e1_rates[ss], endp->e1.scd.demux.num_bits);
 | 
				
			||||||
	endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);
 | 
						endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);
 | 
				
			||||||
	if (!endp->e1.schan) {
 | 
						if (!endp->e1.schan) {
 | 
				
			||||||
@@ -622,7 +626,7 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
 | 
					int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg_tf = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
 | 
						struct msgb *msg_tf = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
	unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
						unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
				
			||||||
	struct osmo_trau_frame tf;
 | 
						struct osmo_trau_frame tf;
 | 
				
			||||||
@@ -679,7 +683,7 @@ int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, s
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
skip:
 | 
					skip:
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_TX_FAIL_CTR]);
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
 | 
				
			||||||
	msgb_free(msg_tf);
 | 
						msgb_free(msg_tf);
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/abis/e1_input.h>
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_e1.h>
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stat_item.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define E1_RATE_MAX 64
 | 
					#define E1_RATE_MAX 64
 | 
				
			||||||
#define E1_OFFS_MAX 8
 | 
					#define E1_OFFS_MAX 8
 | 
				
			||||||
@@ -58,7 +59,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, uint8_t trunk_nr,
 | 
					static char *gen_e1_epname(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;
 | 
				
			||||||
@@ -88,7 +89,6 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&endp->conns);
 | 
						INIT_LLIST_HEAD(&endp->conns);
 | 
				
			||||||
	endp->cfg = trunk->cfg;
 | 
					 | 
				
			||||||
	endp->trunk = trunk;
 | 
						endp->trunk = trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (trunk->trunk_type) {
 | 
						switch (trunk->trunk_type) {
 | 
				
			||||||
@@ -122,6 +122,12 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	 * RSIP is executed), free them all at once. */
 | 
						 * RSIP is executed), free them all at once. */
 | 
				
			||||||
	mgcp_conn_free_all(endp);
 | 
						mgcp_conn_free_all(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We must only decrement the stat item when the endpoint as actually
 | 
				
			||||||
 | 
						 * claimed. An endpoint is claimed when a call-id is set */
 | 
				
			||||||
 | 
						if (endp->callid)
 | 
				
			||||||
 | 
							osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
 | 
				
			||||||
 | 
													 TRUNK_STAT_ENDPOINTS_USED), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Reset endpoint parameters and states */
 | 
						/* Reset endpoint parameters and states */
 | 
				
			||||||
	talloc_free(endp->callid);
 | 
						talloc_free(endp->callid);
 | 
				
			||||||
	endp->callid = NULL;
 | 
						endp->callid = NULL;
 | 
				
			||||||
@@ -129,7 +135,6 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	endp->local_options.string = NULL;
 | 
						endp->local_options.string = NULL;
 | 
				
			||||||
	talloc_free(endp->local_options.codec);
 | 
						talloc_free(endp->local_options.codec);
 | 
				
			||||||
	endp->local_options.codec = NULL;
 | 
						endp->local_options.codec = NULL;
 | 
				
			||||||
	endp->wildcarded_req = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
 | 
						if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
 | 
				
			||||||
		mgcp_e1_endp_release(endp);
 | 
							mgcp_e1_endp_release(endp);
 | 
				
			||||||
@@ -182,12 +187,16 @@ static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Convert all characters in epname to lowercase and strip trunk prefix and
 | 
					
 | 
				
			||||||
 | 
					 /*! Convert all characters in epname to lowercase and strip trunk prefix and
 | 
				
			||||||
 * endpoint name suffix (domain name) from epname. The result is written to
 | 
					 * endpoint name suffix (domain name) from epname. The result is written to
 | 
				
			||||||
 * to the memory pointed at by epname_stripped. The expected size of the
 | 
					 * to the memory pointed at by epname_stripped. The expected size of the
 | 
				
			||||||
 * result is either equal or lower then the length of the input string
 | 
					 * result is either equal or lower then the length of the input string
 | 
				
			||||||
 * (epname) */
 | 
					 * (epname)
 | 
				
			||||||
static void strip_epname(char *epname_stripped, const char *epname,
 | 
					 *  \param[out] epname_stripped pointer to store the stripped ep name.
 | 
				
			||||||
 | 
					 *  \param[in] epname endpoint name to lookup.
 | 
				
			||||||
 | 
					 *  \param[in] trunk where the endpoint is located. */
 | 
				
			||||||
 | 
					void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
 | 
				
			||||||
			 const struct mgcp_trunk *trunk)
 | 
								 const struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
 | 
						osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
 | 
				
			||||||
@@ -214,9 +223,11 @@ static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Find an endpoint specified by its name. If the endpoint can not be found,
 | 
					/*! Find an endpoint of a trunk specified by its name.
 | 
				
			||||||
 * return NULL */
 | 
					 *  \param[in] epname endpoint name to check.
 | 
				
			||||||
static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
 | 
					 *  \param[in] trunk mgcp_trunk that might have this endpoint.
 | 
				
			||||||
 | 
					 *  \returns NULL if no ep found, else endpoint. */
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
				
			||||||
						    const struct mgcp_trunk *trunk)
 | 
											    const struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char epname_stripped[MGCP_ENDPOINT_MAXLEN];
 | 
						char epname_stripped[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
@@ -225,11 +236,11 @@ static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
 | 
				
			|||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Strip irrelevant information from the endpoint name */
 | 
						/* Strip irrelevant information from the endpoint name */
 | 
				
			||||||
	strip_epname(epname_stripped, epname, trunk);
 | 
						mgcp_endp_strip_name(epname_stripped, epname, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < trunk->number_endpoints; i++) {
 | 
						for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
		endp = trunk->endpoints[i];
 | 
							endp = trunk->endpoints[i];
 | 
				
			||||||
		strip_epname(epname_stripped_endp, endp->name, trunk);
 | 
							mgcp_endp_strip_name(epname_stripped_endp, endp->name, trunk);
 | 
				
			||||||
		if (strcmp(epname_stripped_endp, epname_stripped) == 0)
 | 
							if (strcmp(epname_stripped_endp, epname_stripped) == 0)
 | 
				
			||||||
			return endp;
 | 
								return endp;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -237,6 +248,18 @@ static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Check if the given epname refers to a wildcarded request or to a specific
 | 
				
			||||||
 | 
					 *  endpoint.
 | 
				
			||||||
 | 
					 *  \param[in] epname endpoint name to check
 | 
				
			||||||
 | 
					 *  \returns true if epname refers to wildcarded request, else false. */
 | 
				
			||||||
 | 
					bool mgcp_endp_is_wildcarded(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strstr(epname, "*"))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Find an endpoint by its name on a specified trunk.
 | 
					/*! Find an endpoint by its name on a specified trunk.
 | 
				
			||||||
 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
					 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
				
			||||||
 *  \param[in] epname endpoint name to lookup.
 | 
					 *  \param[in] epname endpoint name to lookup.
 | 
				
			||||||
@@ -253,13 +276,12 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			|||||||
	/* At the moment we only support a primitive ('*'-only) method of
 | 
						/* At the moment we only support a primitive ('*'-only) method of
 | 
				
			||||||
	 * wildcarded endpoint searches that picks the next free endpoint on
 | 
						 * wildcarded endpoint searches that picks the next free endpoint on
 | 
				
			||||||
	 * a trunk. */
 | 
						 * a trunk. */
 | 
				
			||||||
	if (strstr(epname, "*")) {
 | 
						if (mgcp_endp_is_wildcarded(epname)) {
 | 
				
			||||||
		endp = find_free_endpoint(trunk);
 | 
							endp = find_free_endpoint(trunk);
 | 
				
			||||||
		if (endp) {
 | 
							if (endp) {
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
				 "(trunk:%d) found free endpoint: %s\n",
 | 
									 "(trunk:%d) found free endpoint: %s\n",
 | 
				
			||||||
				 trunk->trunk_nr, endp->name);
 | 
									 trunk->trunk_nr, endp->name);
 | 
				
			||||||
			endp->wildcarded_req = true;
 | 
					 | 
				
			||||||
			return endp;
 | 
								return endp;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,12 +295,11 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Find an endpoint by its name (if wildcarded request is not
 | 
						/* Find an endpoint by its name (if wildcarded request is not
 | 
				
			||||||
	 * applicable) */
 | 
						 * applicable) */
 | 
				
			||||||
	endp = find_specific_endpoint(epname, trunk);
 | 
						endp = mgcp_endp_find_specific(epname, trunk);
 | 
				
			||||||
	if (endp) {
 | 
						if (endp) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
			 "(trunk:%d) found endpoint: %s\n",
 | 
								 "(trunk:%d) found endpoint: %s\n",
 | 
				
			||||||
			 trunk->trunk_nr, endp->name);
 | 
								 trunk->trunk_nr, endp->name);
 | 
				
			||||||
		endp->wildcarded_req = false;
 | 
					 | 
				
			||||||
		return endp;
 | 
							return endp;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -291,32 +312,6 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the domain name, which is supplied with the endpoint name
 | 
					 | 
				
			||||||
 * matches the configuration. */
 | 
					 | 
				
			||||||
static int check_domain_name(const char *epname, struct mgcp_config *cfg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *domain_to_check;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	domain_to_check = strstr(epname, "@");
 | 
					 | 
				
			||||||
	if (!domain_to_check) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
					 | 
				
			||||||
		     epname, cfg->domain);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Accept any domain if configured as "*" */
 | 
					 | 
				
			||||||
	if (!strcmp(cfg->domain, "*"))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strcmp(domain_to_check+1, cfg->domain) != 0) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
					 | 
				
			||||||
		     epname, cfg->domain);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Find an endpoint by its name, search at all trunks.
 | 
					/*! Find an endpoint by its name, search at all trunks.
 | 
				
			||||||
 *  \param[out] cause, pointer to store cause code, can be NULL.
 | 
					 *  \param[out] cause, pointer to store cause code, can be NULL.
 | 
				
			||||||
 *  \param[in] epname, must contain trunk prefix.
 | 
					 *  \param[in] epname, must contain trunk prefix.
 | 
				
			||||||
@@ -340,10 +335,6 @@ struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			|||||||
	if (!trunk)
 | 
						if (!trunk)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* All endpoint names require a domain as suffix */
 | 
					 | 
				
			||||||
	if (check_domain_name(epname, cfg))
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Identify the endpoint on the trunk */
 | 
						/* Identify the endpoint on the trunk */
 | 
				
			||||||
        endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
 | 
					        endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
 | 
				
			||||||
	if (!endp) {
 | 
						if (!endp) {
 | 
				
			||||||
@@ -555,7 +546,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
				
			|||||||
		epname_check = gen_e1_epname(endp, endp->trunk->cfg->domain,
 | 
							epname_check = gen_e1_epname(endp, endp->trunk->cfg->domain,
 | 
				
			||||||
					     endp->trunk->trunk_nr, ts_nr,
 | 
										     endp->trunk->trunk_nr, ts_nr,
 | 
				
			||||||
					     interlock[i]);
 | 
										     interlock[i]);
 | 
				
			||||||
		endp_check = find_specific_endpoint(epname_check, endp->trunk);
 | 
							endp_check = mgcp_endp_find_specific(epname_check, endp->trunk);
 | 
				
			||||||
		if (!endp_check) {
 | 
							if (!endp_check) {
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "cannot check endpoint availability, overlapping endpoint:%s not found!\n",
 | 
									 "cannot check endpoint availability, overlapping endpoint:%s not found!\n",
 | 
				
			||||||
@@ -619,6 +610,8 @@ int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
 | 
				
			|||||||
	 * connection ids) */
 | 
						 * connection ids) */
 | 
				
			||||||
	endp->callid = talloc_strdup(endp, callid);
 | 
						endp->callid = talloc_strdup(endp, callid);
 | 
				
			||||||
	OSMO_ASSERT(endp->callid);
 | 
						OSMO_ASSERT(endp->callid);
 | 
				
			||||||
 | 
						osmo_stat_item_inc(osmo_stat_item_group_get_item(endp->trunk->stats.common,
 | 
				
			||||||
 | 
												 TRUNK_STAT_ENDPOINTS_USED), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate resources */
 | 
						/* Allocate resources */
 | 
				
			||||||
	switch (endp->trunk->trunk_type) {
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										745
									
								
								src/libosmo-mgcp/mgcp_iuup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										745
									
								
								src/libosmo-mgcp/mgcp_iuup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,745 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All rights not specifically granted under this license are reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Pau Espin Pedrol
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/byteswap.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/gsm/iuup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					#include <osmocom/netif/amr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_iuup.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGW_IUUP_MSGB_SIZE 4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_iuup_rnl_config def_configure_req = {
 | 
				
			||||||
 | 
						.transparent = false,
 | 
				
			||||||
 | 
						.active = true,
 | 
				
			||||||
 | 
						.supported_versions_mask = 0x0003,
 | 
				
			||||||
 | 
						.num_rfci = 0,
 | 
				
			||||||
 | 
						.num_subflows = 0,
 | 
				
			||||||
 | 
						.IPTIs_present = false,
 | 
				
			||||||
 | 
						.t_init = { .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT },
 | 
				
			||||||
 | 
						.t_ta = { .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT },
 | 
				
			||||||
 | 
						.t_rc = { .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find a destination connection. */
 | 
				
			||||||
 | 
					static struct mgcp_conn *_find_dst_conn(struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* NOTE: This code path runs every time an RTP packet is received. The
 | 
				
			||||||
 | 
						 * function mgcp_find_dst_conn() we use to determine the detination
 | 
				
			||||||
 | 
						 * connection will iterate the connection list inside the endpoint.
 | 
				
			||||||
 | 
						 * Since list iterations are quite costly, we will figure out the
 | 
				
			||||||
 | 
						 * destination only once and use the optional private data pointer of
 | 
				
			||||||
 | 
						 * the connection to cache the destination connection pointer. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
 | 
						if (!conn->priv) {
 | 
				
			||||||
 | 
							conn_dst = mgcp_find_dst_conn(conn);
 | 
				
			||||||
 | 
							conn->priv = conn_dst;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							conn_dst = (struct mgcp_conn *)conn->priv;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return conn_dst;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find RFCI containing all 0 sizes, -1 if not found. irp is an Initialization.ind prim */
 | 
				
			||||||
 | 
					static int _find_rfci_no_data(struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						uint8_t rfci_cnt = 0;
 | 
				
			||||||
 | 
						/* Find RFCI containing NO_DATA: */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
				
			||||||
 | 
							struct osmo_iuup_rfci *rfci = &irp->u.status.u.initialization.rfci[i];
 | 
				
			||||||
 | 
							int j;
 | 
				
			||||||
 | 
							bool is_no_data;
 | 
				
			||||||
 | 
							if (!rfci->used)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							rfci_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							is_no_data = true;
 | 
				
			||||||
 | 
							for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++) {
 | 
				
			||||||
 | 
								if (rfci->subflow_sizes[j]) {
 | 
				
			||||||
 | 
									is_no_data = false;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (is_no_data)
 | 
				
			||||||
 | 
								return rfci->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* early loop termination: */
 | 
				
			||||||
 | 
							if (rfci_cnt == irp->u.status.u.initialization.num_subflows)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Lookup RFCI to use for specific AMR codec type. -1 if none found */
 | 
				
			||||||
 | 
					static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t ft)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int8_t i;
 | 
				
			||||||
 | 
						uint8_t rfci_cnt = 0;
 | 
				
			||||||
 | 
						unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
 | 
				
			||||||
 | 
						OSMO_ASSERT(irp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: cache this somehow */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
				
			||||||
 | 
							struct osmo_iuup_rfci *rfci = &irp->u.status.u.initialization.rfci[i];
 | 
				
			||||||
 | 
							int j;
 | 
				
			||||||
 | 
							unsigned num_bits;
 | 
				
			||||||
 | 
							if (!rfci->used)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							rfci_cnt++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							num_bits = 0;
 | 
				
			||||||
 | 
							for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++)
 | 
				
			||||||
 | 
								num_bits += rfci->subflow_sizes[j];
 | 
				
			||||||
 | 
							if (match_bytes == (num_bits + 7)/8)
 | 
				
			||||||
 | 
								return rfci->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* early loop termination: */
 | 
				
			||||||
 | 
							if (rfci_cnt == irp->u.status.u.initialization.num_subflows)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Helper function to configure IuUP layer FSM as Init-Passive, based on default config */
 | 
				
			||||||
 | 
					static int _conn_iuup_configure_as_passive(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn_rtp->iuup.active_init = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Tx CONFIG.req */
 | 
				
			||||||
 | 
						irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
				
			||||||
 | 
						irp->u.config = def_configure_req;
 | 
				
			||||||
 | 
						irp->u.config.active = conn_rtp->iuup.active_init;
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) == 0)
 | 
				
			||||||
 | 
							conn_rtp->iuup.configured = true;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Helper function to configure IuUP layer FSM as Init-Active, based on received
 | 
				
			||||||
 | 
					 * RNL Status-Init primitive from the sister IuUP connection we will bridge to. */
 | 
				
			||||||
 | 
					static int _conn_iuup_configure_as_active(struct mgcp_conn_rtp *conn_rtp, struct osmo_iuup_rnl_prim *init_ind)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp = init_ind;
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp2;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						bool prev_output_enabled;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn_rtp->iuup.active_init = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find RFCI containing NO_DATA: */
 | 
				
			||||||
 | 
						conn_rtp->iuup.rfci_id_no_data = _find_rfci_no_data(init_ind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Copy over the rfci_id_no_data, since we reuse the same subflow set: */
 | 
				
			||||||
 | 
						msg = msgb_copy_c(conn_rtp->conn, irp->oph.msg, "iuup-init-copy");
 | 
				
			||||||
 | 
						conn_rtp->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
 | 
				
			||||||
 | 
						conn_rtp->iuup.init_ind->oph.msg = msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Tx CONFIG.req */
 | 
				
			||||||
 | 
						irp2 = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
				
			||||||
 | 
						irp2->u.config.transparent = false;
 | 
				
			||||||
 | 
						irp2->u.config.active = conn_rtp->iuup.active_init;
 | 
				
			||||||
 | 
						irp2->u.config.data_pdu_type = irp->u.status.u.initialization.data_pdu_type;
 | 
				
			||||||
 | 
						irp2->u.config.supported_versions_mask = def_configure_req.supported_versions_mask;
 | 
				
			||||||
 | 
						irp2->u.config.num_rfci = irp->u.status.u.initialization.num_rfci;
 | 
				
			||||||
 | 
						irp2->u.config.num_subflows = irp->u.status.u.initialization.num_subflows;
 | 
				
			||||||
 | 
						irp2->u.config.IPTIs_present = irp->u.status.u.initialization.IPTIs_present;
 | 
				
			||||||
 | 
						memcpy(irp2->u.config.rfci, irp->u.status.u.initialization.rfci, sizeof(irp2->u.config.rfci));
 | 
				
			||||||
 | 
						irp2->u.config.t_init = def_configure_req.t_init;
 | 
				
			||||||
 | 
						irp2->u.config.t_ta = def_configure_req.t_ta;
 | 
				
			||||||
 | 
						irp2->u.config.t_rc = def_configure_req.t_rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We need to force allowance of RTP containing Init-ACK back: */
 | 
				
			||||||
 | 
						prev_output_enabled = conn_rtp->end.output_enabled;
 | 
				
			||||||
 | 
						conn_rtp->end.output_enabled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp2)) == 0)
 | 
				
			||||||
 | 
							conn_rtp->iuup.configured = true;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn_rtp->end.output_enabled = prev_output_enabled;
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Helper function to push an RTP+IuUP pkt up to the IuUP layer FSM through the
 | 
				
			||||||
 | 
					 * TNL primitive interface. */
 | 
				
			||||||
 | 
					static int _conn_iuup_rtp_pl_up(struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Send RTP payload (IuUP) up the stack: */
 | 
				
			||||||
 | 
						struct osmo_iuup_tnl_prim *itp;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg->l2h = msgb_data(msg) + sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						itp = osmo_iuup_tnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, MGW_IUUP_MSGB_SIZE);
 | 
				
			||||||
 | 
						itp->oph.msg->l2h = msgb_put(itp->oph.msg, msgb_l2len(msg));
 | 
				
			||||||
 | 
						memcpy(itp->oph.msg->l2h, msgb_l2(msg), msgb_l2len(msg));
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_tnl_prim_up(conn_rtp->iuup.iui, itp)) != 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed passing IuUP-Init to IuUP layer\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int check_rtp_iuup(const struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t min_size = sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
						/* Check there's at least 2 bytes of RTP payload (IuUP header). This is
 | 
				
			||||||
 | 
						 ** mainly to avoid 0-byte payload copy cases */
 | 
				
			||||||
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr) + 2) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "RTP-IuUP packet too short (%u < %zu)\n",
 | 
				
			||||||
 | 
								     msgb_length(msg), min_size);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an IuUP sister
 | 
				
			||||||
 | 
					 * conn in the endpoint. The function takes ownsership of the irp */
 | 
				
			||||||
 | 
					static int bridge_iuup_to_iuup_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If we are not configured and we received bridged data, it means
 | 
				
			||||||
 | 
						 * conn_rtp_src is already configured and INITed, and we can infer
 | 
				
			||||||
 | 
						 * conn_rtp_src is Init-passive (RNC side), so conn_rtp_dst needs to be
 | 
				
			||||||
 | 
						 * configured as INIT-active: */
 | 
				
			||||||
 | 
						if (!conn_rtp_dst->iuup.configured) {
 | 
				
			||||||
 | 
							OSMO_ASSERT(conn_rtp_src->iuup.init_ind);
 | 
				
			||||||
 | 
							rc = _conn_iuup_configure_as_active(conn_rtp_dst, conn_rtp_src->iuup.init_ind);
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								msgb_free(irp->oph.msg);
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We simply forward the msg, without freeing it: */
 | 
				
			||||||
 | 
						talloc_steal(conn_rtp_dst->conn, irp->oph.msg);
 | 
				
			||||||
 | 
						irp->oph.operation = PRIM_OP_REQUEST;
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_rnl_prim_down(conn_rtp_dst->iuup.iui, irp)) != 0)
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp_dst, LOGL_ERROR, "Failed Tx data down to IuUP layer\n");
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an RTP (no IuUP)
 | 
				
			||||||
 | 
					 * sister conn in the endpoint. The function takes ownsership of the irp */
 | 
				
			||||||
 | 
					static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
 | 
				
			||||||
 | 
						uint8_t frame_nr = irp->u.data.frame_nr;
 | 
				
			||||||
 | 
						uint8_t fqc = irp->u.data.fqc;
 | 
				
			||||||
 | 
						struct msgb *msg = irp->oph.msg;
 | 
				
			||||||
 | 
						ssize_t amr_length = 0;
 | 
				
			||||||
 | 
						int ft;
 | 
				
			||||||
 | 
						uint8_t *amr_data;
 | 
				
			||||||
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
 | 
						struct amr_hdr *amr_hdr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
 | 
				
			||||||
 | 
						if (ft < 0) {
 | 
				
			||||||
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "Unknown AMR format for size %u\n", msgb_l3len(msg));
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return ft;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_pull_to_l3(msg);
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
				
			||||||
 | 
							amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
				
			||||||
 | 
							amr_hdr->cmr = 15; /* no change */
 | 
				
			||||||
 | 
							amr_hdr->f = 0;
 | 
				
			||||||
 | 
							amr_hdr->q = !fqc;
 | 
				
			||||||
 | 
							amr_hdr->ft = ft & 0xff;
 | 
				
			||||||
 | 
							amr_hdr->pad1 = 0;
 | 
				
			||||||
 | 
							amr_hdr->pad2 = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							OSMO_ASSERT(msgb_tailroom(msg) >= 2);
 | 
				
			||||||
 | 
							msgb_put(msg, 2);
 | 
				
			||||||
 | 
							osmo_amr_iuup_to_bwe(msgb_data(msg), msgb_length(msg) - 2, msgb_length(msg) + 2);
 | 
				
			||||||
 | 
							/* fill bwe header */
 | 
				
			||||||
 | 
							amr_data = msgb_data(msg);
 | 
				
			||||||
 | 
							/* CMR no change      | follow bit | ft (3 of 4 bits) */
 | 
				
			||||||
 | 
							amr_data[0] = 15 << 4 | (0 << 3) | (ft >> 1);
 | 
				
			||||||
 | 
							amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
 | 
				
			||||||
 | 
							amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
 | 
				
			||||||
 | 
							msgb_trim(msg, amr_length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
 | 
				
			||||||
 | 
						*rtp_hdr = (struct rtp_hdr){
 | 
				
			||||||
 | 
							.csrc_count = 0,
 | 
				
			||||||
 | 
							.extension = 0,
 | 
				
			||||||
 | 
							.padding = 0,
 | 
				
			||||||
 | 
							.version = 0,
 | 
				
			||||||
 | 
							.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
				
			||||||
 | 
							.marker = 0,
 | 
				
			||||||
 | 
							.sequence = frame_nr,
 | 
				
			||||||
 | 
							.timestamp = 0,
 | 
				
			||||||
 | 
							.ssrc = 0
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handle RNL Data primitive received from the IuUP layer FSM: Bridge it to the
 | 
				
			||||||
 | 
					 * sister connection in the endpoint: */
 | 
				
			||||||
 | 
					static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp_dst;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn_dst = _find_dst_conn(conn_rtp_src->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* There is no destination conn, stop here */
 | 
				
			||||||
 | 
						if (!conn_dst) {
 | 
				
			||||||
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "no connection to forward an incoming IuUP payload to\n");
 | 
				
			||||||
 | 
							rc = -1;
 | 
				
			||||||
 | 
							goto free_ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The destination conn is not an RTP/IuUP connection */
 | 
				
			||||||
 | 
						if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "unable to find suitable destination conn\n");
 | 
				
			||||||
 | 
							 rc = -1;
 | 
				
			||||||
 | 
							goto free_ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						conn_rtp_dst = &conn_dst->u.rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (conn_rtp_dst->type) {
 | 
				
			||||||
 | 
						case MGCP_RTP_IUUP:
 | 
				
			||||||
 | 
							return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
				
			||||||
 | 
						case MGCP_RTP_DEFAULT:
 | 
				
			||||||
 | 
							return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
				
			||||||
 | 
						case MGCP_OSMUX_BSC:
 | 
				
			||||||
 | 
						case MGCP_OSMUX_BSC_NAT:
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "Forward of IuUP payload to RTP connection type %u not supported!\n",
 | 
				
			||||||
 | 
								 conn_rtp_dst->type);
 | 
				
			||||||
 | 
							rc = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					free_ret:
 | 
				
			||||||
 | 
						msgb_free(irp->oph.msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handle RNL Status-Init primitive received from the IuUP layer FSM.
 | 
				
			||||||
 | 
					 * Potentially configure sister conn as IuUP Init-Active: */
 | 
				
			||||||
 | 
					static int _conn_iuup_rx_rnl_status_init(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp_dst;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn_rtp_src->iuup.init_ind) {
 | 
				
			||||||
 | 
							/* We received more than one IuUP Initialization. It's probably
 | 
				
			||||||
 | 
							 * a retransmission, so simply ignore it (lower layers take care
 | 
				
			||||||
 | 
							 * of ACKing it). */
 | 
				
			||||||
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_INFO,
 | 
				
			||||||
 | 
							  "Ignoring potential IuUP Initialization retrans\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg = msgb_copy_c(conn_rtp_src->conn, irp->oph.msg, "iuup-init-copy");
 | 
				
			||||||
 | 
						conn_rtp_src->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
 | 
				
			||||||
 | 
						conn_rtp_src->iuup.init_ind->oph.msg = msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find RFCI containing NO_DATA: */
 | 
				
			||||||
 | 
						conn_rtp_src->iuup.rfci_id_no_data = _find_rfci_no_data(irp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn_dst = _find_dst_conn(conn_rtp_src->conn);
 | 
				
			||||||
 | 
						/* If not yet there, peer will potentially be IuUP-Initialized later
 | 
				
			||||||
 | 
						 * when we attempt to bridge audio towards it. See bridge_iuup_to_iuup_peer() */
 | 
				
			||||||
 | 
						if (!conn_dst)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						conn_rtp_dst = &conn_dst->u.rtp;
 | 
				
			||||||
 | 
						if (!mgcp_conn_rtp_is_iuup(conn_rtp_dst))
 | 
				
			||||||
 | 
							return 0; /* Nothing to do */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We received IuUP parameters on the peer (RNC), Init actively this conn (against CN): */
 | 
				
			||||||
 | 
						if (!conn_rtp_dst->iuup.configured)
 | 
				
			||||||
 | 
							rc = _conn_iuup_configure_as_active(conn_rtp_dst, irp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handle RNL Status primitives received from the IuUP layer FSM: */
 | 
				
			||||||
 | 
					static int _conn_iuup_rx_rnl_status(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (irp->u.status.procedure) {
 | 
				
			||||||
 | 
						case IUUP_PROC_INIT:
 | 
				
			||||||
 | 
							rc = _conn_iuup_rx_rnl_status_init(conn_rtp_src, irp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case IUUP_PROC_RATE_CTRL:
 | 
				
			||||||
 | 
						case IUUP_PROC_TIME_ALIGN:
 | 
				
			||||||
 | 
						case IUUP_PROC_ERR_EVENT:
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp_src, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "Received IuUP RNL STATUS procedure type %u not handled\n",
 | 
				
			||||||
 | 
								     irp->u.status.procedure);
 | 
				
			||||||
 | 
							rc = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Received RNL primitive from the IuUP layer FSM containing IuUP Status or
 | 
				
			||||||
 | 
					 * data. Continue pushing it up the stack, either IuUP Status or Data: */
 | 
				
			||||||
 | 
					static int _conn_iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp_src = ctx;
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;
 | 
				
			||||||
 | 
						struct msgb *msg = oph->msg;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (OSMO_PRIM_HDR(&irp->oph)) {
 | 
				
			||||||
 | 
						case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION):
 | 
				
			||||||
 | 
							/* we pass ownsership of msg here: */
 | 
				
			||||||
 | 
							rc = _conn_iuup_rx_rnl_data(conn_rtp_src, irp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION):
 | 
				
			||||||
 | 
							rc = _conn_iuup_rx_rnl_status(conn_rtp_src, irp);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Send |RTP+IuUP| data down the stack of the specified destination connection.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint (for configuration, logging).
 | 
				
			||||||
 | 
					 *  \param[in] buf buffer that contains the |RTP+IuUP| data.
 | 
				
			||||||
 | 
					 *  \param[in] len length of the buffer that contains the |RTP+IuUP| data.
 | 
				
			||||||
 | 
					 *  \param[in] conn_src associated source connection.
 | 
				
			||||||
 | 
					 *  \param[in] conn_dst associated destination connection.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
 | 
					static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			||||||
 | 
							   struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*! When no destination connection is available (e.g. when only one
 | 
				
			||||||
 | 
						 *  connection in loopback mode exists), then the source connection
 | 
				
			||||||
 | 
						 *  shall be specified as destination connection */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mgcp_rtp_end *rtp_end;
 | 
				
			||||||
 | 
						struct mgcp_rtp_state *rtp_state;
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
						int buflen = msgb_length(msg);
 | 
				
			||||||
 | 
						char *dest_name;
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_src);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_dst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering IuUP packet...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note: In case of loopback configuration, both, the source and the
 | 
				
			||||||
 | 
						 * destination will point to the same connection. */
 | 
				
			||||||
 | 
						rtp_end = &conn_dst->end;
 | 
				
			||||||
 | 
						rtp_state = &conn_src->state;
 | 
				
			||||||
 | 
						dest_name = conn_dst->conn->name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Ensure we have an alternative SSRC in case we need it, see also
 | 
				
			||||||
 | 
						 * gen_rtp_header() */
 | 
				
			||||||
 | 
						if (rtp_state->alt_rtp_tx_ssrc == 0)
 | 
				
			||||||
 | 
							rtp_state->alt_rtp_tx_ssrc = rand();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rtp_end->output_enabled) {
 | 
				
			||||||
 | 
							rtpconn_rate_ctr_add(conn_dst, endp, RTP_DROPPED_PACKETS_CTR, 1);
 | 
				
			||||||
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "output disabled, drop to %s %s "
 | 
				
			||||||
 | 
								 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
 | 
								 dest_name,
 | 
				
			||||||
 | 
								 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
 | 
								 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Specs say, in IuUP, the RTP seqnum and timestamp should actually be
 | 
				
			||||||
 | 
						 * ignored by the receiver, but still it's useful for debug purposes
 | 
				
			||||||
 | 
						 * to set it. Moreover, it seems ip.access nano3g produces much worse
 | 
				
			||||||
 | 
						 * audio output on the air side if timestamp is not set properly. */
 | 
				
			||||||
 | 
						hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
				
			||||||
 | 
						hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
				
			||||||
 | 
						hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
							 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
 | 
							 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
 | 
							 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
 | 
						forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
				
			||||||
 | 
							     msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
 | 
				
			||||||
 | 
								    (char *)hdr, buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len <= 0)
 | 
				
			||||||
 | 
							return len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
 | 
				
			||||||
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
				
			||||||
 | 
						rtp_state->alt_rtp_tx_sequence++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
 | 
				
			||||||
 | 
					 * socket towards destination peer. */
 | 
				
			||||||
 | 
					static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp_dst = ctx;
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst = conn_rtp_dst->conn;
 | 
				
			||||||
 | 
						struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_src;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						struct rtp_hdr *rtph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg = oph->msg;
 | 
				
			||||||
 | 
						talloc_steal(conn_rtp_dst->conn, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_pull_to_l2(msg);
 | 
				
			||||||
 | 
						rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
 | 
				
			||||||
 | 
						/* TODO: fill rtph properly: */
 | 
				
			||||||
 | 
						*rtph = (struct rtp_hdr){
 | 
				
			||||||
 | 
							.csrc_count = 0,
 | 
				
			||||||
 | 
							.extension = 0,
 | 
				
			||||||
 | 
							.padding = 0,
 | 
				
			||||||
 | 
							.version = 2,
 | 
				
			||||||
 | 
							.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
				
			||||||
 | 
							.marker = 0,
 | 
				
			||||||
 | 
							.sequence = 0,
 | 
				
			||||||
 | 
							.timestamp = 0,
 | 
				
			||||||
 | 
							.ssrc = 0
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The destination of the destination conn is the source conn, right? */
 | 
				
			||||||
 | 
						conn_src = _find_dst_conn(conn_dst);
 | 
				
			||||||
 | 
						if (!conn_src) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp_dst, LOGL_NOTICE,
 | 
				
			||||||
 | 
								     "Couldn't find source conn for IuUP dst conn\n");
 | 
				
			||||||
 | 
							/* If there's no sister connection we are either still
 | 
				
			||||||
 | 
							 * initializing (so we want to send back Init (ACK)), or we are
 | 
				
			||||||
 | 
							 * probably in loopback mode anyway, so use dst as src. */
 | 
				
			||||||
 | 
							conn_src = conn_dst;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mgcp_send_iuup(conn_dst->endp, msg, &conn_src->u.rtp, conn_rtp_dst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Used to upgrade a regular RTP connection (MGCP_RTP_DEFAULT) to become a IuUP
 | 
				
			||||||
 | 
					 * connection (MGCP_RTP_IUUP) */
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						conn_rtp->type = MGCP_RTP_IUUP;
 | 
				
			||||||
 | 
						conn_rtp->iuup.iui = osmo_iuup_instance_alloc(conn_rtp->conn, conn_rtp->conn->id);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_rtp->iuup.iui);
 | 
				
			||||||
 | 
						osmo_iuup_instance_set_user_prim_cb(conn_rtp->iuup.iui, _conn_iuup_user_prim_cb, conn_rtp);
 | 
				
			||||||
 | 
						osmo_iuup_instance_set_transport_prim_cb(conn_rtp->iuup.iui, _conn_iuup_transport_prim_cb, conn_rtp);
 | 
				
			||||||
 | 
						conn_rtp->iuup.rfci_id_no_data = -1;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Cleanup specific IuUP connection (MGCP_RTP_IUUP) state, allocated by mgcp_conn_iuup_init() */
 | 
				
			||||||
 | 
					void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_iuup_instance_free(conn_rtp->iuup.iui);
 | 
				
			||||||
 | 
						conn_rtp->iuup.iui = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Received RTP+IuUP pkt from socket of conn_rtp_src, build a TNL primitive to
 | 
				
			||||||
 | 
					 * push it further up the stack to the IuUP layer FSM to handle and/or bridge it */
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp_src = mc->conn_src;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						bool force_output_enabled = false;
 | 
				
			||||||
 | 
						bool prev_output_enabled;
 | 
				
			||||||
 | 
						struct osmo_sockaddr prev_rem_addr;
 | 
				
			||||||
 | 
						uint16_t prev_rem_rtp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp_src));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((rc = check_rtp_iuup(conn_rtp_src, msg)) < 0)
 | 
				
			||||||
 | 
							goto free_ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!conn_rtp_src->iuup.configured) {
 | 
				
			||||||
 | 
							/* We received the first message without sending any, the peer is the active side (RNC). */
 | 
				
			||||||
 | 
							rc = _conn_iuup_configure_as_passive(conn_rtp_src);
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							/* We need to force allowance of RTP containing Init-ACK back: */
 | 
				
			||||||
 | 
							prev_output_enabled = conn_rtp_src->end.output_enabled;
 | 
				
			||||||
 | 
							conn_rtp_src->end.output_enabled = true;
 | 
				
			||||||
 | 
							force_output_enabled = true;
 | 
				
			||||||
 | 
							/* Fill in the peer address so that we can send Init-ACK back: */
 | 
				
			||||||
 | 
							prev_rem_addr = conn_rtp_src->end.addr;
 | 
				
			||||||
 | 
							prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
 | 
				
			||||||
 | 
							conn_rtp_src->end.addr = *mc->from_addr;
 | 
				
			||||||
 | 
							conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (force_output_enabled) {
 | 
				
			||||||
 | 
							conn_rtp_src->end.output_enabled = prev_output_enabled;
 | 
				
			||||||
 | 
							conn_rtp_src->end.addr = prev_rem_addr;
 | 
				
			||||||
 | 
							conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					free_ret:
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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: */
 | 
				
			||||||
 | 
					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 rtp_hdr *rtph;
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						int iuup_length = 0;
 | 
				
			||||||
 | 
						int8_t rfci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Tx RNL-DATA.req */
 | 
				
			||||||
 | 
						rtph = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
						msgb_pull(msg, sizeof(*rtph));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: validate amr packets */
 | 
				
			||||||
 | 
						irp = osmo_iuup_rnl_prim_alloc(conn_dest_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
				
			||||||
 | 
						irp->u.data.frame_nr = htons(rtph->sequence) % 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: CMR handling & multiple frames handling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
 | 
				
			||||||
 | 
								     conn_src_rtp->end.codec->subtype_name);
 | 
				
			||||||
 | 
							goto free_ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
 | 
				
			||||||
 | 
							struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
 | 
				
			||||||
 | 
							if (msgb_length(msg) < (sizeof(*amr_hdr))) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
				
			||||||
 | 
									     "Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (amr_hdr->ft >= AMR_FT_MAX) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ((rfci =  _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, amr_hdr->ft)) < 0) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							irp->u.data.fqc = amr_hdr->q;
 | 
				
			||||||
 | 
							irp->u.data.rfci = rfci;
 | 
				
			||||||
 | 
							msgb_pull(msg, 2);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
 | 
				
			||||||
 | 
							int8_t ft;
 | 
				
			||||||
 | 
							if (msgb_length(msg) < 2) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
				
			||||||
 | 
									     "Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
 | 
				
			||||||
 | 
							if (ft >= AMR_FT_MAX) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ((rfci =  _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, ft)) < 0) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
 | 
				
			||||||
 | 
								goto free_ret;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							irp->u.data.fqc = ((amr_bwe_hdr[1] & 0x40) >> 6);
 | 
				
			||||||
 | 
							irp->u.data.rfci = rfci;
 | 
				
			||||||
 | 
							rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed convert the RTP/AMR to IuUP payload\n");
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							msgb_trim(msg, iuup_length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
 | 
				
			||||||
 | 
						memcpy(irp->oph.msg->l3h, msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_rnl_prim_down(conn_dest_rtp->iuup.iui, irp)) != 0)
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed Tx RTP payload down the IuUP layer\n");
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					free_ret:
 | 
				
			||||||
 | 
						msgb_free(irp->oph.msg);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Build IuUP RNL Data primitive from msg containing dummy content and send it
 | 
				
			||||||
 | 
					 * down the IuUP layer towards the destination as IuUP/RTP: */
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn_rtp->iuup.rfci_id_no_data == -1) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_NOTICE, "No RFCI NO_DATA found, unable to send dummy packet\n");
 | 
				
			||||||
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
				
			||||||
 | 
						irp->u.data.frame_nr = 0;
 | 
				
			||||||
 | 
						irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
 | 
				
			||||||
 | 
						irp->u.data.rfci = conn_rtp->iuup.rfci_id_no_data;
 | 
				
			||||||
 | 
						irp->oph.msg->l3h = irp->oph.msg->tail;
 | 
				
			||||||
 | 
						if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) != 0) {
 | 
				
			||||||
 | 
							LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed Tx RTP dummy payload down the IuUP layer\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -31,6 +31,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! 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
 | 
				
			||||||
@@ -109,8 +110,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Special handling for RTP connections */
 | 
						/* Special handling for RTP connections */
 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		conn->u.rtp.end.output_enabled =
 | 
							conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
				
			||||||
		    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
				
			||||||
@@ -120,7 +120,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Special handling für RTP connections */
 | 
						/* Special handling für RTP connections */
 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
 | 
							LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
				
			||||||
			 conn->u.rtp.end.output_enabled);
 | 
								 conn->u.rtp.end.output_enabled);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,24 +132,19 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
					/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
				
			||||||
 *  \param[out] pdata caller provided memory to store the parsing results
 | 
					 *  \param[out] pdata caller provided memory to store the parsing results.
 | 
				
			||||||
 *  \param[in] data mgcp message string
 | 
					 *  \param[in] data mgcp message string.
 | 
				
			||||||
 *  \returns when the status line was complete and transaction_id and
 | 
					 *  \returns 0 when the status line was complete and parseable, negative (MGCP
 | 
				
			||||||
 *  endp out parameters are set, -1 on error */
 | 
					 *  cause code) on error. */
 | 
				
			||||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
					int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i = 0;
 | 
						int i = 0;
 | 
				
			||||||
	char *elem, *save = NULL;
 | 
						char *elem, *save = NULL;
 | 
				
			||||||
	int cause;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! This function will parse the header part of the received
 | 
						/*! This function will parse the header part of the received
 | 
				
			||||||
	 *  MGCP message. The parsing results are stored in pdata.
 | 
						 *  MGCP message. The parsing results are stored in pdata. */
 | 
				
			||||||
	 *  The function will also automatically search the pool with
 | 
					 | 
				
			||||||
	 *  available endpoints in order to find an endpoint that matches
 | 
					 | 
				
			||||||
	 *  the endpoint string in in the header */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(data);
 | 
						OSMO_ASSERT(data);
 | 
				
			||||||
	pdata->trans = "000000";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (elem = strtok_r(data, " ", &save); elem;
 | 
						for (elem = strtok_r(data, " ", &save); elem;
 | 
				
			||||||
	     elem = strtok_r(NULL, " ", &save)) {
 | 
						     elem = strtok_r(NULL, " ", &save)) {
 | 
				
			||||||
@@ -158,13 +153,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
			pdata->trans = elem;
 | 
								pdata->trans = elem;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 1:
 | 
							case 1:
 | 
				
			||||||
			pdata->endp = mgcp_endp_by_name(&cause, elem, pdata->cfg);
 | 
								pdata->epname = elem;
 | 
				
			||||||
			if (!pdata->endp) {
 | 
					 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
				     "Unable to find Endpoint `%s'\n", elem);
 | 
					 | 
				
			||||||
				OSMO_ASSERT(cause < 0);
 | 
					 | 
				
			||||||
				return cause;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 2:
 | 
							case 2:
 | 
				
			||||||
			if (strcasecmp("MGCP", elem)) {
 | 
								if (strcasecmp("MGCP", elem)) {
 | 
				
			||||||
@@ -174,11 +163,8 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 3:
 | 
							case 3:
 | 
				
			||||||
			if (strcmp("1.0", elem)) {
 | 
								if (strcmp("1.0", elem))
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
 | 
					 | 
				
			||||||
				     "not supported\n", elem);
 | 
					 | 
				
			||||||
				return -528;
 | 
									return -528;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		i++;
 | 
							i++;
 | 
				
			||||||
@@ -186,8 +172,6 @@ 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");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
 | 
				
			||||||
		pdata->trans = "000000";
 | 
					 | 
				
			||||||
		pdata->endp = NULL;
 | 
					 | 
				
			||||||
		return -510;
 | 
							return -510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -224,22 +208,24 @@ 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)
 | 
					 *  \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 1 when line seems plausible, 0 on error */
 | 
					 *  \returns true when line seems plausible, false on error */
 | 
				
			||||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
 | 
					bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, 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) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							if (endp)
 | 
				
			||||||
		     "Wrong MGCP option format: '%s' on %s\n",
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
				
			||||||
		     line, endp->name);
 | 
							else
 | 
				
			||||||
		return 0;
 | 
								LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: A couple more checks wouldn't hurt... */
 | 
						/* FIXME: A couple more checks wouldn't hurt... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 1;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Check if the specified callid seems plausible.
 | 
					/*! Check if the specified callid seems plausible.
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -116,7 +116,7 @@ static struct osmux_handle *
 | 
				
			|||||||
osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_port)
 | 
					osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmux_handle *h;
 | 
						struct osmux_handle *h;
 | 
				
			||||||
	struct mgcp_config *cfg = conn->conn->endp->cfg;
 | 
						struct mgcp_config *cfg = conn->conn->endp->trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	h = talloc_zero(osmux, struct osmux_handle);
 | 
						h = talloc_zero(osmux, struct osmux_handle);
 | 
				
			||||||
	if (!h)
 | 
						if (!h)
 | 
				
			||||||
@@ -375,7 +375,7 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* not any further processing dummy messages */
 | 
						/* not any further processing dummy messages */
 | 
				
			||||||
	if (msg->data[0] == MGCP_DUMMY_LOAD)
 | 
						if (mgcp_is_rtp_dummy_payload(msg))
 | 
				
			||||||
		return osmux_handle_dummy(cfg, &addr, msg);
 | 
							return osmux_handle_dummy(cfg, &addr, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rem = msg->len;
 | 
						rem = msg->len;
 | 
				
			||||||
@@ -418,13 +418,13 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, cfg, 0);
 | 
						osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, cfg, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
 | 
						ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port,
 | 
				
			||||||
 | 
									cfg->endp_dscp, cfg->endp_priority);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
 | 
				
			||||||
		     cfg->osmux_addr, cfg->osmux_port);
 | 
							     cfg->osmux_addr, cfg->osmux_port);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = osmo_fd_register(&osmux_fd);
 | 
						ret = osmo_fd_register(&osmux_fd);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
@@ -460,7 +460,7 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct in6_addr addr_unset = {};
 | 
						struct in6_addr addr_unset = {};
 | 
				
			||||||
	static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
						static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
				
			||||||
	uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 | 
						uint16_t osmux_dummy = endp->trunk->cfg->osmux_dummy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if osmux is enabled for the specified connection */
 | 
						/* Check if osmux is enabled for the specified connection */
 | 
				
			||||||
	if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
 | 
						if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -22,9 +22,14 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdatomic.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <osmocom/core/stats.h>
 | 
					#include <osmocom/core/stats.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stat_item.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
					#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
					static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
				
			||||||
@@ -58,7 +63,6 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
						[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
				
			||||||
	    { "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
						    { "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
				
			||||||
	[MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
 | 
						[MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
 | 
				
			||||||
	[MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = { "crcx:conn_rejected", "connection rejected by policy." },
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
 | 
						[MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
 | 
				
			||||||
	[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
 | 
						[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
 | 
				
			||||||
	[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
 | 
						[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
 | 
				
			||||||
@@ -90,8 +94,6 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
						[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
				
			||||||
	    { "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
						    { "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
				
			||||||
	[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
 | 
						[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
 | 
				
			||||||
	[MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },
 | 
					 | 
				
			||||||
	[MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -105,15 +107,12 @@ const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
					static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
				
			||||||
	[MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
 | 
						[MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
 | 
				
			||||||
	[MGCP_DLCX_FAIL_WILDCARD] = { "dlcx:wildcard", "wildcard names in DLCX commands are unsupported." },
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
 | 
						[MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
 | 
				
			||||||
	[MGCP_DLCX_FAIL_INVALID_CALLID] =
 | 
						[MGCP_DLCX_FAIL_INVALID_CALLID] =
 | 
				
			||||||
	    { "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
 | 
						    { "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
 | 
				
			||||||
	[MGCP_DLCX_FAIL_INVALID_CONNID] =
 | 
						[MGCP_DLCX_FAIL_INVALID_CONNID] =
 | 
				
			||||||
	    { "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
 | 
						    { "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
 | 
				
			||||||
	[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
 | 
						[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
 | 
				
			||||||
	[MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },
 | 
					 | 
				
			||||||
	[MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -126,9 +125,9 @@ const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
 | 
					static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
 | 
				
			||||||
	[E1_I460_TRAU_RX_FAIL_CTR] = {"e1:rx_fail", "Inbound I.460 TRAU failures."},
 | 
						[E1_I460_TRAU_RX_FAIL_CTR] = { "e1:rx_fail", "Inbound I.460 TRAU failures." },
 | 
				
			||||||
	[E1_I460_TRAU_TX_FAIL_CTR] = {"e1:tx_fail", "Outbound I.460 TRAU failures."},
 | 
						[E1_I460_TRAU_TX_FAIL_CTR] = { "e1:tx_fail", "Outbound I.460 TRAU failures." },
 | 
				
			||||||
	[E1_I460_TRAU_MUX_EMPTY_CTR] = {"e1:i460", "Outbound I.460 MUX queue empty."}
 | 
						[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			||||||
@@ -147,83 +146,180 @@ const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
						.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
 | 
					/*! allocate global rate counters
 | 
				
			||||||
 | 
					 *  (called once at startup).
 | 
				
			||||||
 | 
					 *  \param[in] cfg mgw configuration for which the rate counters are allocated.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_ratectr_global_alloc(struct mgcp_config *cfg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rate_ctr_group_free(rate_ctr_group);
 | 
						struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
 | 
				
			||||||
	return 0;
 | 
						static atomic_uint general_rate_ctr_index = 0;
 | 
				
			||||||
}
 | 
						char ctr_name[512];
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! allocate global rate counters into a given rate counter struct
 | 
					 | 
				
			||||||
 *  (called once at startup)
 | 
					 | 
				
			||||||
 *  \param[in] ctx talloc context.
 | 
					 | 
				
			||||||
 *  \param[out] ratectr struct that holds the counters
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure */
 | 
					 | 
				
			||||||
int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* FIXME: Each new rate counter group requires a unique index. At the
 | 
					 | 
				
			||||||
	 * moment we generate an index using a counter, but perhaps there is
 | 
					 | 
				
			||||||
	 * a better way of assigning indices? */
 | 
					 | 
				
			||||||
	static unsigned int general_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->mgcp_general_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_general_ctr_group == NULL) {
 | 
				
			||||||
		ratectr->mgcp_general_ctr_group =
 | 
							ratectr->mgcp_general_ctr_group =
 | 
				
			||||||
		    rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
 | 
							    rate_ctr_group_alloc(cfg, &mgcp_general_ctr_group_desc, general_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->mgcp_general_ctr_group)
 | 
							if (!ratectr->mgcp_general_ctr_group)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->mgcp_general_ctr_group, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s:general", cfg->domain);
 | 
				
			||||||
		general_rate_ctr_index++;
 | 
							rate_ctr_group_set_name(ratectr->mgcp_general_ctr_group, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate trunk specific rate counters into a given rate counter struct
 | 
					/*! free global rate counters
 | 
				
			||||||
 *  (called once on trunk initialization)
 | 
					 *  (called once at process shutdown).
 | 
				
			||||||
 *  \param[in] ctx talloc context.
 | 
					 *  \param[in] cfg mgw configuration for which the rate counters are allocated. */
 | 
				
			||||||
 *  \param[out] ratectr struct that holds the counters
 | 
					void mgcp_ratectr_global_free(struct mgcp_config *cfg)
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure */
 | 
					 | 
				
			||||||
int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* FIXME: see comment in mgcp_ratectr_global_alloc()  */
 | 
						struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
 | 
				
			||||||
	static unsigned int crcx_rate_ctr_index = 0;
 | 
					
 | 
				
			||||||
	static unsigned int mdcx_rate_ctr_index = 0;
 | 
						if (ratectr->mgcp_general_ctr_group) {
 | 
				
			||||||
	static unsigned int dlcx_rate_ctr_index = 0;
 | 
							rate_ctr_group_free(ratectr->mgcp_general_ctr_group);
 | 
				
			||||||
	static unsigned int all_rtp_conn_rate_ctr_index = 0;
 | 
							ratectr->mgcp_general_ctr_group = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate trunk specific rate counters
 | 
				
			||||||
 | 
					 *  (called once on trunk initialization).
 | 
				
			||||||
 | 
					 *  \param[in] trunk mgw trunk for which the rate counters are allocated.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure */
 | 
				
			||||||
 | 
					int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
 | 
				
			||||||
 | 
						static atomic_uint crcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static atomic_uint mdcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static atomic_uint dlcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static atomic_uint all_rtp_conn_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						char ctr_name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
				
			||||||
		ratectr->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
 | 
							ratectr->mgcp_crcx_ctr_group =
 | 
				
			||||||
 | 
							    rate_ctr_group_alloc(trunk, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->mgcp_crcx_ctr_group)
 | 
							if (!ratectr->mgcp_crcx_ctr_group)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->mgcp_crcx_ctr_group, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:crcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
		crcx_rate_ctr_index++;
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->mgcp_crcx_ctr_group, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->mgcp_mdcx_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_mdcx_ctr_group == NULL) {
 | 
				
			||||||
		ratectr->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
 | 
							ratectr->mgcp_mdcx_ctr_group =
 | 
				
			||||||
 | 
							    rate_ctr_group_alloc(trunk, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->mgcp_mdcx_ctr_group)
 | 
							if (!ratectr->mgcp_mdcx_ctr_group)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->mgcp_mdcx_ctr_group, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:mdcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
		mdcx_rate_ctr_index++;
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->mgcp_mdcx_ctr_group, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->mgcp_dlcx_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_dlcx_ctr_group == NULL) {
 | 
				
			||||||
		ratectr->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
 | 
							ratectr->mgcp_dlcx_ctr_group =
 | 
				
			||||||
 | 
							    rate_ctr_group_alloc(trunk, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->mgcp_dlcx_ctr_group)
 | 
							if (!ratectr->mgcp_dlcx_ctr_group)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->mgcp_dlcx_ctr_group, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:dlcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
		dlcx_rate_ctr_index++;
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->mgcp_dlcx_ctr_group, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->all_rtp_conn_stats == NULL) {
 | 
						if (ratectr->all_rtp_conn_stats == NULL) {
 | 
				
			||||||
		ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
 | 
							ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc,
 | 
				
			||||||
								 all_rtp_conn_rate_ctr_index);
 | 
													   all_rtp_conn_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->all_rtp_conn_stats)
 | 
							if (!ratectr->all_rtp_conn_stats)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:rtp_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
		all_rtp_conn_rate_ctr_index++;
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->e1_stats == NULL) {
 | 
					
 | 
				
			||||||
		ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index);
 | 
						/* E1 specific */
 | 
				
			||||||
 | 
						if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
 | 
				
			||||||
 | 
							ratectr->e1_stats = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
 | 
				
			||||||
		if (!ratectr->e1_stats)
 | 
							if (!ratectr->e1_stats)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		talloc_set_destructor(ratectr->e1_stats, free_rate_counter_group);
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:e1", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
		mdcx_rate_ctr_index++;
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->e1_stats, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free trunk specific rate counters
 | 
				
			||||||
 | 
					 *  (called once when trunk is freed).
 | 
				
			||||||
 | 
					 *  \param[in] trunk mgw trunk on which the rate counters are allocated. */
 | 
				
			||||||
 | 
					void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ratectr->mgcp_crcx_ctr_group) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->mgcp_crcx_ctr_group);
 | 
				
			||||||
 | 
							ratectr->mgcp_crcx_ctr_group = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->mgcp_mdcx_ctr_group) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->mgcp_mdcx_ctr_group);
 | 
				
			||||||
 | 
							ratectr->mgcp_mdcx_ctr_group = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->mgcp_dlcx_ctr_group) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->mgcp_dlcx_ctr_group);
 | 
				
			||||||
 | 
							ratectr->mgcp_dlcx_ctr_group = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_rtp_conn_stats) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->all_rtp_conn_stats);
 | 
				
			||||||
 | 
							ratectr->all_rtp_conn_stats = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* E1 specific */
 | 
				
			||||||
 | 
						if (ratectr->e1_stats) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->e1_stats);
 | 
				
			||||||
 | 
							ratectr->e1_stats = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct osmo_stat_item_desc trunk_stat_desc[] = {
 | 
				
			||||||
 | 
						[TRUNK_STAT_ENDPOINTS_TOTAL] = { "endpoints:total",
 | 
				
			||||||
 | 
										 "Number of endpoints that exist on the trunk",
 | 
				
			||||||
 | 
										 "", 60, 0 },
 | 
				
			||||||
 | 
						[TRUNK_STAT_ENDPOINTS_USED] = { "endpoints:used",
 | 
				
			||||||
 | 
										"Number of endpoints in use",
 | 
				
			||||||
 | 
										"", 60, 0 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct osmo_stat_item_group_desc trunk_statg_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "trunk",
 | 
				
			||||||
 | 
						.group_description = "mgw trunk",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_items = ARRAY_SIZE(trunk_stat_desc),
 | 
				
			||||||
 | 
						.item_desc = trunk_stat_desc,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate trunk specific stat items
 | 
				
			||||||
 | 
					 *  (called once on trunk initialization).
 | 
				
			||||||
 | 
					 *  \param[in] trunk for which the stat items are allocated.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_stat_trunk *stats = &trunk->stats;
 | 
				
			||||||
 | 
						static unsigned int common_stat_index = 0;
 | 
				
			||||||
 | 
						char stat_name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stats->common = osmo_stat_item_group_alloc(trunk, &trunk_statg_desc, common_stat_index);
 | 
				
			||||||
 | 
						if (!stats->common)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						snprintf(stat_name, sizeof(stat_name), "%s-%u:common", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
 | 
							 trunk->trunk_nr);
 | 
				
			||||||
 | 
						osmo_stat_item_group_set_name(stats->common, stat_name);
 | 
				
			||||||
 | 
						common_stat_index++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free trunk specific stat items
 | 
				
			||||||
 | 
					 *  (called once when trunk is freed).
 | 
				
			||||||
 | 
					 *  \param[in] trunk on which the stat items are allocated. */
 | 
				
			||||||
 | 
					void mgcp_stat_trunk_free(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_stat_trunk *stats = &trunk->stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stats->common) {
 | 
				
			||||||
 | 
							osmo_stat_item_group_free(stats->common);
 | 
				
			||||||
 | 
							stats->common = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,7 +98,7 @@ static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
 | 
				
			|||||||
/* Helper function to update codec map information with additional data from
 | 
					/* Helper function to update codec map information with additional data from
 | 
				
			||||||
 * SDP, called from: mgcp_parse_sdp_data() */
 | 
					 * SDP, called from: mgcp_parse_sdp_data() */
 | 
				
			||||||
static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
					static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			||||||
			  int payload, const char *audio_name)
 | 
								  int payload_type, const char *audio_name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,7 +110,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			|||||||
		/* Note: We can only update payload codecs that already exist
 | 
							/* Note: We can only update payload codecs that already exist
 | 
				
			||||||
		 * in our codec list. If we get an unexpected payload type,
 | 
							 * in our codec list. If we get an unexpected payload type,
 | 
				
			||||||
		 * we just drop it */
 | 
							 * we just drop it */
 | 
				
			||||||
		if (codecs[i].payload_type != payload)
 | 
							if (codecs[i].payload_type != payload_type)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
							if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
				
			||||||
@@ -127,7 +127,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
 | 
						LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload_type,
 | 
				
			||||||
	     audio_name);
 | 
						     audio_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -334,7 +334,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int payload;
 | 
						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;
 | 
				
			||||||
@@ -355,8 +355,8 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			/* skip these SDP attributes */
 | 
								/* skip these SDP attributes */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'a':
 | 
							case 'a':
 | 
				
			||||||
			if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
 | 
								if (sscanf(line, "a=rtpmap:%d %63s", &payload_type, audio_name) == 2) {
 | 
				
			||||||
				codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
 | 
									codecs_update(tmp_ctx, codecs, codecs_used, payload_type, audio_name);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -394,11 +394,13 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
				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(&rtp->addr, line) < 0) {
 | 
				
			||||||
 | 
									talloc_free(tmp_ctx);
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if (p->endp)
 | 
								if (endp)
 | 
				
			||||||
				/* TODO: Check spec: We used the bare endpoint number before,
 | 
									/* TODO: Check spec: We used the bare endpoint number before,
 | 
				
			||||||
				 * now we use the endpoint name as a whole? Is this allowed? */
 | 
									 * now we use the endpoint name as a whole? Is this allowed? */
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
									LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
@@ -437,7 +439,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	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,
 | 
							      rtp->codecs[i].payload_type,
 | 
				
			||||||
		      rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
 | 
							      strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
						LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
				
			||||||
@@ -574,7 +576,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	OSMO_ASSERT(addr);
 | 
						OSMO_ASSERT(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
						/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
				
			||||||
	endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
						endp->trunk->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
				
			||||||
					      &codec, &fmtp_extra,
 | 
										      &codec, &fmtp_extra,
 | 
				
			||||||
					      (struct mgcp_conn_rtp *)conn);
 | 
										      (struct mgcp_conn_rtp *)conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -599,7 +601,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		payload_types[0] = payload_type;
 | 
							payload_types[0] = payload_type;
 | 
				
			||||||
		if (mgcp_conn_rtp_is_osmux(conn))
 | 
							if (mgcp_conn_rtp_is_osmux(conn))
 | 
				
			||||||
			local_port = endp->cfg->osmux_port;
 | 
								local_port = endp->trunk->cfg->osmux_port;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			local_port = conn->end.local_port;
 | 
								local_port = conn->end.local_port;
 | 
				
			||||||
		rc = add_audio(sdp, payload_types, 1, local_port);
 | 
							rc = add_audio(sdp, payload_types, 1, local_port);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,12 +28,18 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_stat.h>
 | 
					#include <osmocom/mgcp/mgcp_stat.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
 | 
					/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
 | 
				
			||||||
 | 
					#if defined(__has_attribute)
 | 
				
			||||||
 | 
					#if __has_attribute(no_sanitize)
 | 
				
			||||||
 | 
					__attribute__((no_sanitize("undefined")))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
					void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
						struct mgcp_rtp_state *state = &conn->state;
 | 
				
			||||||
	struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*expected = state->stats.cycles + state->stats.max_seq;
 | 
						*expected = state->stats.cycles + state->stats.max_seq;
 | 
				
			||||||
	*expected = *expected - state->stats.base_seq + 1;
 | 
						*expected = *expected - state->stats.base_seq + 1;
 | 
				
			||||||
@@ -74,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	int ploss;
 | 
						int ploss;
 | 
				
			||||||
	int nchars;
 | 
						int nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_rx = &conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR];
 | 
						struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *packets_tx = &conn->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR];
 | 
						struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_tx = &conn->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR];
 | 
						struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	calc_loss(conn, &expected, &ploss);
 | 
						calc_loss(conn, &expected, &ploss);
 | 
				
			||||||
	jitter = calc_jitter(&conn->state);
 | 
						jitter = calc_jitter(&conn->state);
 | 
				
			||||||
@@ -93,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	str += nchars;
 | 
						str += nchars;
 | 
				
			||||||
	str_len -= nchars;
 | 
						str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->conn->endp->cfg->osmux != OSMUX_USAGE_OFF) {
 | 
						if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
 | 
				
			||||||
		/* Error Counter */
 | 
							/* Error Counter */
 | 
				
			||||||
		nchars = snprintf(str, str_len,
 | 
							nchars = snprintf(str, str_len,
 | 
				
			||||||
				  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
									  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										207
									
								
								src/libosmo-mgcp/mgcp_threads_queue.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/libosmo-mgcp/mgcp_threads_queue.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,207 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Eric Wild
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <inttypes.h>
 | 
				
			||||||
 | 
					#include <stdatomic.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/eventfd.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <talloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_threads_queue.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					classic lamport circular lockfree spsc queue:
 | 
				
			||||||
 | 
					every "side" only writes its own ptr, but may read the other sides ptr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					notify reader using eventfd as soon as element is added, reader then reads until
 | 
				
			||||||
 | 
					read fails
 | 
				
			||||||
 | 
					-> reader pops in a loop until FALSE and might get spurious events because it
 | 
				
			||||||
 | 
					read before it was notified, which is fine
 | 
				
			||||||
 | 
					-> writing pushes *the same data* in a loop until TRUE, blocks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shutting this down requires
 | 
				
			||||||
 | 
					1) to stop reading and pushing
 | 
				
			||||||
 | 
					2) ONE side to take care of the eventfds
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct spsc *spsc_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr, bool blockw)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spsc *q = talloc_zero_size(talloc_ctx, sizeof(struct spsc) + sizeof(uintptr_t) * count);
 | 
				
			||||||
 | 
						atomic_init(&q->readptr, 0);
 | 
				
			||||||
 | 
						atomic_init(&q->writeptr, 0);
 | 
				
			||||||
 | 
						q->efd_r = eventfd(0, blockr ? 0 : EFD_NONBLOCK);
 | 
				
			||||||
 | 
						q->efd_w = eventfd(1, blockw ? 0 : EFD_NONBLOCK);
 | 
				
			||||||
 | 
						q->count = count;
 | 
				
			||||||
 | 
						q->size_per_buf = size_per_buf;
 | 
				
			||||||
 | 
						q->buf = talloc_zero_size(q, size_per_buf * count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < count; i++)
 | 
				
			||||||
 | 
							q->data[i] = (uintptr_t)q->buf + i * size_per_buf;
 | 
				
			||||||
 | 
						return q;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void spsc_deinit(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						talloc_free(q->buf);
 | 
				
			||||||
 | 
						close(q->efd_r);
 | 
				
			||||||
 | 
						close(q->efd_w);
 | 
				
			||||||
 | 
						talloc_free(q);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t spsc_check_r(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint64_t efdr;
 | 
				
			||||||
 | 
						return read(q->efd_r, &efdr, sizeof(uint64_t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static ssize_t spsc_check_w(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint64_t efdr;
 | 
				
			||||||
 | 
						return read(q->efd_w, &efdr, sizeof(uint64_t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void spsc_notify_r(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint64_t efdu = 1;
 | 
				
			||||||
 | 
						write(q->efd_r, &efdu, sizeof(uint64_t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static void spsc_notify_w(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint64_t efdu = 1;
 | 
				
			||||||
 | 
						write(q->efd_w, &efdu, sizeof(uint64_t));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Adds element to the queue by copying the data.
 | 
				
			||||||
 | 
					 *  \param[in] q queue.
 | 
				
			||||||
 | 
					 *  \param[in] elem input buffer, must match the originally configured queue buffer size!.
 | 
				
			||||||
 | 
					 *  \returns true if queue was not full and element was successfully pushed */
 | 
				
			||||||
 | 
					bool spsc_push(struct spsc *q, void *elem)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t cur_wp, cur_rp;
 | 
				
			||||||
 | 
						cur_wp = atomic_load_explicit(&q->writeptr, memory_order_relaxed);
 | 
				
			||||||
 | 
						cur_rp = atomic_load_explicit(&q->readptr, memory_order_acquire);
 | 
				
			||||||
 | 
						if ((cur_wp + 1) % q->count == cur_rp) {
 | 
				
			||||||
 | 
							spsc_check_w(q); /* blocks, ensures next (!) call succeeds */
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						memcpy((void *)q->data[cur_wp], elem, q->size_per_buf);
 | 
				
			||||||
 | 
						atomic_store_explicit(&q->writeptr, (cur_wp + 1) % q->count, memory_order_release);
 | 
				
			||||||
 | 
						spsc_notify_r(q); /* fine after release */
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Reads the read-fd of the queue, which, depending on settings passed on queue creation, blocks.
 | 
				
			||||||
 | 
					 * This function can be used to deliberately wait for a non-empty queue on the read side.
 | 
				
			||||||
 | 
					 *  \param[in] q queue.
 | 
				
			||||||
 | 
					 *  \returns result of reading the fd. */
 | 
				
			||||||
 | 
					ssize_t spsc_prep_pop(struct spsc *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return spsc_check_r(q);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Removes element from the queue by copying the data.
 | 
				
			||||||
 | 
					 *  \param[in] q queue.
 | 
				
			||||||
 | 
					 *  \param[in] elem output buffer, must match the originally configured queue buffer size!.
 | 
				
			||||||
 | 
					 *  \returns true if queue was not empty and element was successfully removed */
 | 
				
			||||||
 | 
					bool spsc_pop(struct spsc *q, void *elem)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t cur_wp, cur_rp;
 | 
				
			||||||
 | 
						cur_wp = atomic_load_explicit(&q->writeptr, memory_order_acquire);
 | 
				
			||||||
 | 
						cur_rp = atomic_load_explicit(&q->readptr, memory_order_relaxed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cur_wp == cur_rp) /* blocks via prep_pop */
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						memcpy(elem, (void *)q->data[cur_rp], q->size_per_buf);
 | 
				
			||||||
 | 
						atomic_store_explicit(&q->readptr, (cur_rp + 1) % q->count, memory_order_release);
 | 
				
			||||||
 | 
						spsc_notify_w(q);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Creates a bidirectional queue channel that consists of two queues, one in each direction,
 | 
				
			||||||
 | 
					 *  commonly referred to as a and b side.
 | 
				
			||||||
 | 
					 *  \param[in] talloc_ctx allocation context.
 | 
				
			||||||
 | 
					 *  \param[in] count number of buffers per queue.
 | 
				
			||||||
 | 
					 *  \param[in] size_per_buf size of buffers per queue.
 | 
				
			||||||
 | 
					 *  \param[in] blockr_a should reading the a-side read fd block?.
 | 
				
			||||||
 | 
					 *  \param[in] blockw_a should reading the a-side write fd block?.
 | 
				
			||||||
 | 
					 *  \param[in] blockr_b should reading the b-side read fd block?.
 | 
				
			||||||
 | 
					 *  \param[in] blockw_b should reading the b-side write fd block?.
 | 
				
			||||||
 | 
					  *  \returns queue channel */
 | 
				
			||||||
 | 
					struct qchan spsc_chan_init_ex(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr_a,
 | 
				
			||||||
 | 
								       bool blockw_a, bool blockr_b, bool blockw_b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct qchan q;
 | 
				
			||||||
 | 
						q.a = spsc_init(talloc_ctx, count, size_per_buf, blockr_a, blockw_a);
 | 
				
			||||||
 | 
						q.b = spsc_init(talloc_ctx, count, size_per_buf, blockr_b, blockw_b);
 | 
				
			||||||
 | 
						return q;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Creates a bidirectional queue channel that consists of two queues, one in each direction,
 | 
				
			||||||
 | 
					 *  commonly referred to as a and b side.
 | 
				
			||||||
 | 
					 *  \param[in] talloc_ctx allocation context.
 | 
				
			||||||
 | 
					 *  \param[in] count number of buffers per queue.
 | 
				
			||||||
 | 
					 *  \param[in] size_per_buf size of buffers per queue.
 | 
				
			||||||
 | 
					 *  \returns queue channel */
 | 
				
			||||||
 | 
					struct qchan spsc_chan_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return spsc_chan_init_ex(talloc_ctx, count, size_per_buf, false, true, false, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Closes a bidirectional queue channel.
 | 
				
			||||||
 | 
					 *  \param[in] q queue */
 | 
				
			||||||
 | 
					void spsc_chan_close(struct qchan *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						spsc_deinit(q->a);
 | 
				
			||||||
 | 
						spsc_deinit(q->b);
 | 
				
			||||||
 | 
						free(q);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
				
			||||||
 | 
					 *  \param[in] q queue channel.
 | 
				
			||||||
 | 
					 *  \returns fd */
 | 
				
			||||||
 | 
					int spsc_get_a_rdfd(struct qchan *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return q->a->efd_r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
				
			||||||
 | 
					 *  \param[in] q queue channel.
 | 
				
			||||||
 | 
					 *  \returns fd */
 | 
				
			||||||
 | 
					int spsc_get_b_rdfd(struct qchan *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return q->b->efd_r;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
				
			||||||
 | 
					 *  \param[in] q queue channel.
 | 
				
			||||||
 | 
					 *  \returns fd */
 | 
				
			||||||
 | 
					int spsc_get_a_wrfd(struct qchan *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return q->a->efd_w;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
				
			||||||
 | 
					 *  \param[in] q queue channel.
 | 
				
			||||||
 | 
					 *  \returns fd */
 | 
				
			||||||
 | 
					int spsc_get_b_wrfd(struct qchan *q)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return q->b->efd_w;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,14 +27,31 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_e1.h>
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
#include <osmocom/abis/e1_input.h>
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stat_item.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate trunk and add it (if required) to the trunk list.
 | 
					const struct value_string mgcp_trunk_type_strs[] = {
 | 
				
			||||||
 | 
						{ MGCP_TRUNK_VIRTUAL,		"virtual" },
 | 
				
			||||||
 | 
						{ MGCP_TRUNK_E1,		"e1" },
 | 
				
			||||||
 | 
						{ 0, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Free trunk, this function is automatically called by talloc_free when the trunk is freed. It does not free the
 | 
				
			||||||
 | 
					 * endpoints on the trunk, this must be done separately before freeing the trunk. */
 | 
				
			||||||
 | 
					static int trunk_free_talloc_destructor(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_del(&trunk->entry);
 | 
				
			||||||
 | 
						mgcp_ratectr_trunk_free(trunk);
 | 
				
			||||||
 | 
						mgcp_stat_trunk_free(trunk);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate trunk and add it to the trunk list.
 | 
				
			||||||
 *  (called once at startup by VTY).
 | 
					 *  (called once at startup by VTY).
 | 
				
			||||||
 *  \param[in] cfg mgcp configuration.
 | 
					 *  \param[in] cfg mgcp configuration.
 | 
				
			||||||
 *  \param[in] ttype trunk type.
 | 
					 *  \param[in] ttype trunk type.
 | 
				
			||||||
 *  \param[in] nr trunk number.
 | 
					 *  \param[in] nr trunk number.
 | 
				
			||||||
 *  \returns pointer to allocated trunk, NULL on failure. */
 | 
					 *  \returns pointer to allocated trunk, NULL on failure. */
 | 
				
			||||||
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
 | 
					struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,7 +74,9 @@ struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_typ
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	llist_add_tail(&trunk->entry, &cfg->trunks);
 | 
						llist_add_tail(&trunk->entry, &cfg->trunks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
 | 
						mgcp_ratectr_trunk_alloc(trunk);
 | 
				
			||||||
 | 
						mgcp_stat_trunk_alloc(trunk);
 | 
				
			||||||
 | 
						talloc_set_destructor(trunk, trunk_free_talloc_destructor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return trunk;
 | 
						return trunk;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -104,7 +123,7 @@ int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
 | 
				
			|||||||
	OSMO_ASSERT(number_endpoints < 65534);
 | 
						OSMO_ASSERT(number_endpoints < 65534);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* allocate pointer array for the endpoints */
 | 
						/* allocate pointer array for the endpoints */
 | 
				
			||||||
	trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
 | 
						trunk->endpoints = talloc_zero_array(trunk, struct mgcp_endpoint*,
 | 
				
			||||||
					     number_endpoints);
 | 
										     number_endpoints);
 | 
				
			||||||
	if (!trunk->endpoints)
 | 
						if (!trunk->endpoints)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -121,7 +140,8 @@ int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* make the endpoints we just created available to the MGW code */
 | 
						/* make the endpoints we just created available to the MGW code */
 | 
				
			||||||
	trunk->number_endpoints = number_endpoints;
 | 
						trunk->number_endpoints = number_endpoints;
 | 
				
			||||||
 | 
						osmo_stat_item_set(osmo_stat_item_group_get_item(trunk->stats.common, TRUNK_STAT_ENDPOINTS_TOTAL),
 | 
				
			||||||
 | 
								   trunk->number_endpoints);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -165,7 +185,7 @@ int mgcp_trunk_equip(struct mgcp_trunk *trunk)
 | 
				
			|||||||
 *  \param[in] ttype trunk type.
 | 
					 *  \param[in] ttype trunk type.
 | 
				
			||||||
 *  \param[in] nr trunk number.
 | 
					 *  \param[in] nr trunk number.
 | 
				
			||||||
 *  \returns pointer to trunk configuration, NULL on error. */
 | 
					 *  \returns pointer to trunk configuration, NULL on error. */
 | 
				
			||||||
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
 | 
					struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -178,9 +198,9 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Made public for unit-testing, do not use from outside this file */
 | 
					/* Made public for unit-testing, do not use from outside this file */
 | 
				
			||||||
int e1_trunk_nr_from_epname(const char *epname)
 | 
					int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long int trunk_nr;
 | 
						unsigned long trunk_nr_temp;
 | 
				
			||||||
	size_t prefix_len;
 | 
						size_t prefix_len;
 | 
				
			||||||
	char *str_trunk_nr_end;
 | 
						char *str_trunk_nr_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,13 +209,41 @@ int e1_trunk_nr_from_epname(const char *epname)
 | 
				
			|||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	errno = 0;
 | 
						errno = 0;
 | 
				
			||||||
	trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
 | 
						trunk_nr_temp = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
 | 
				
			||||||
	if (errno == ERANGE || trunk_nr > 64
 | 
						if (errno == ERANGE || trunk_nr_temp > 64
 | 
				
			||||||
	    || epname + prefix_len == str_trunk_nr_end
 | 
						    || epname + prefix_len == str_trunk_nr_end
 | 
				
			||||||
	    || str_trunk_nr_end[0] != '/')
 | 
						    || str_trunk_nr_end[0] != '/')
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	else
 | 
						else {
 | 
				
			||||||
		return trunk_nr;
 | 
							*trunk_nr = (unsigned int)trunk_nr_temp;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the domain name, which is supplied with the endpoint name
 | 
				
			||||||
 | 
					 * matches the configuration. */
 | 
				
			||||||
 | 
					static int check_domain_name(const char *epname, const struct mgcp_config *cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *domain_to_check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						domain_to_check = strstr(epname, "@");
 | 
				
			||||||
 | 
						if (!domain_to_check) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
				
			||||||
 | 
							     epname, cfg->domain);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Accept any domain if configured as "*" */
 | 
				
			||||||
 | 
						if (!strcmp(cfg->domain, "*"))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(domain_to_check+1, cfg->domain) != 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
				
			||||||
 | 
							     epname, cfg->domain);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Find a trunk by the trunk prefix in the endpoint name.
 | 
					/*! Find a trunk by the trunk prefix in the endpoint name.
 | 
				
			||||||
@@ -206,18 +254,23 @@ struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	size_t prefix_len;
 | 
						size_t prefix_len;
 | 
				
			||||||
	char epname_lc[MGCP_ENDPOINT_MAXLEN];
 | 
						char epname_lc[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
	int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
 | 
						osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
 | 
				
			||||||
	epname = epname_lc;
 | 
						epname = epname_lc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* All endpoint names require a domain as suffix */
 | 
				
			||||||
 | 
						if (check_domain_name(epname, cfg))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
 | 
						prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
 | 
				
			||||||
	if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
 | 
						if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
 | 
				
			||||||
		return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
							return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname(epname);
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, epname);
 | 
				
			||||||
	if (trunk_nr >= 0)
 | 
						if (rc == 0)
 | 
				
			||||||
		return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
 | 
							return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Earlier versions of osmo-mgw were accepting endpoint names
 | 
						/* Earlier versions of osmo-mgw were accepting endpoint names
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,17 +65,17 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, "mgcp%s", VTY_NEWLINE);
 | 
						vty_out(vty, "mgcp%s", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " domain %s%s", g_cfg->domain, VTY_NEWLINE);
 | 
						vty_out(vty, " domain %s%s", g_cfg->domain, VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->local_ip)
 | 
						if (strlen(g_cfg->local_ip))
 | 
				
			||||||
		vty_out(vty, "  local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
 | 
							vty_out(vty, "  local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
 | 
						vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
 | 
						vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " rtp port-range %u %u%s",
 | 
						vty_out(vty, " rtp port-range %u %u%s",
 | 
				
			||||||
		g_cfg->net_ports.range_start, g_cfg->net_ports.range_end,
 | 
							g_cfg->net_ports.range_start, g_cfg->net_ports.range_end,
 | 
				
			||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->net_ports.bind_addr_v4)
 | 
						if (strlen(g_cfg->net_ports.bind_addr_v4))
 | 
				
			||||||
		vty_out(vty, " rtp bind-ip %s%s",
 | 
							vty_out(vty, " rtp bind-ip %s%s",
 | 
				
			||||||
			g_cfg->net_ports.bind_addr_v4, VTY_NEWLINE);
 | 
								g_cfg->net_ports.bind_addr_v4, VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->net_ports.bind_addr_v6)
 | 
						if (strlen(g_cfg->net_ports.bind_addr_v6))
 | 
				
			||||||
		vty_out(vty, " rtp bind-ip-v6 %s%s",
 | 
							vty_out(vty, " rtp bind-ip-v6 %s%s",
 | 
				
			||||||
			g_cfg->net_ports.bind_addr_v6, VTY_NEWLINE);
 | 
								g_cfg->net_ports.bind_addr_v6, VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->net_ports.bind_addr_probe)
 | 
						if (g_cfg->net_ports.bind_addr_probe)
 | 
				
			||||||
@@ -83,6 +83,8 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		vty_out(vty, " no rtp ip-probing%s", VTY_NEWLINE);
 | 
							vty_out(vty, " no rtp ip-probing%s", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
 | 
						vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (g_cfg->endp_priority)
 | 
				
			||||||
 | 
							vty_out(vty, " rtp socket-priority %d%s", g_cfg->endp_priority, VTY_NEWLINE);
 | 
				
			||||||
	if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
 | 
						if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
 | 
				
			||||||
		vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
 | 
							vty_out(vty, " rtp keep-alive once%s", VTY_NEWLINE);
 | 
				
			||||||
	else if (trunk->keepalive_interval)
 | 
						else if (trunk->keepalive_interval)
 | 
				
			||||||
@@ -120,7 +122,7 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
							trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " %sallow-transcoding%s",
 | 
						vty_out(vty, " %sallow-transcoding%s",
 | 
				
			||||||
		trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
							trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->call_agent_addr)
 | 
						if (strlen(g_cfg->call_agent_addr))
 | 
				
			||||||
		vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
 | 
							vty_out(vty, " call-agent ip %s%s", g_cfg->call_agent_addr,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->force_ptime > 0)
 | 
						if (g_cfg->force_ptime > 0)
 | 
				
			||||||
@@ -167,11 +169,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
						struct rate_ctr *rx_packets, *rx_bytes;
 | 
				
			||||||
	struct rate_ctr *dropped_packets;
 | 
						struct rate_ctr *dropped_packets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tx_packets = &conn->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR];
 | 
						tx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	tx_bytes = &conn->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR];
 | 
						tx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
	rx_packets = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
 | 
						rx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	rx_bytes = &conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR];
 | 
						rx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	dropped_packets = &conn->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR];
 | 
						dropped_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_DROPPED_PACKETS_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty,
 | 
						vty_out(vty,
 | 
				
			||||||
		"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
							"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
@@ -198,11 +200,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
					static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			||||||
			  int trunk_nr, enum mgcp_trunk_type trunk_type, int show_stats)
 | 
								  unsigned int trunk_nr, enum mgcp_trunk_type trunk_type, int show_stats)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, "%s trunk %d endpoint %s:%s",
 | 
						vty_out(vty, "%s trunk %u endpoint %s:%s",
 | 
				
			||||||
		trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr, endp->name, VTY_NEWLINE);
 | 
							trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1", trunk_nr, endp->name, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, "   Availability: %s%s",
 | 
						vty_out(vty, "   Availability: %s%s",
 | 
				
			||||||
		mgcp_endp_avail(endp) ? "available" : "not in service", VTY_NEWLINE);
 | 
							mgcp_endp_avail(endp) ? "available" : "not in service", VTY_NEWLINE);
 | 
				
			||||||
@@ -216,7 +218,7 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			|||||||
		vty_out(vty, "   CONN: %s%s", mgcp_conn_dump(conn), VTY_NEWLINE);
 | 
							vty_out(vty, "   CONN: %s%s", mgcp_conn_dump(conn), VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (show_stats) {
 | 
							if (show_stats) {
 | 
				
			||||||
			if (endp->cfg->conn_timeout) {
 | 
								if (endp->trunk->cfg->conn_timeout) {
 | 
				
			||||||
				struct timeval remaining;
 | 
									struct timeval remaining;
 | 
				
			||||||
				osmo_timer_remaining(&conn->watchdog, NULL, &remaining);
 | 
									osmo_timer_remaining(&conn->watchdog, NULL, &remaining);
 | 
				
			||||||
				vty_out(vty, "   Currently remaining timeout (seconds): %d.%06d%s",
 | 
									vty_out(vty, "   Currently remaining timeout (seconds): %d.%06d%s",
 | 
				
			||||||
@@ -299,9 +301,10 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dump_trunk(struct vty *vty, struct mgcp_trunk *trunk, int show_stats)
 | 
					static void dump_trunk(struct vty *vty, struct mgcp_trunk *trunk, int show_stats, int active_only)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
						int active_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, "%s trunk %d with %d endpoints:%s",
 | 
						vty_out(vty, "%s trunk %d with %d endpoints:%s",
 | 
				
			||||||
		trunk->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
 | 
							trunk->trunk_type == MGCP_TRUNK_VIRTUAL ? "Virtual" : "E1",
 | 
				
			||||||
@@ -314,29 +317,30 @@ static void dump_trunk(struct vty *vty, struct mgcp_trunk *trunk, int show_stats
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < trunk->number_endpoints; ++i) {
 | 
						for (i = 0; i < trunk->number_endpoints; ++i) {
 | 
				
			||||||
		struct mgcp_endpoint *endp = trunk->endpoints[i];
 | 
							struct mgcp_endpoint *endp = trunk->endpoints[i];
 | 
				
			||||||
		dump_endpoint(vty, endp, trunk->trunk_nr, trunk->trunk_type,
 | 
							if (!active_only || !llist_empty(&endp->conns)) {
 | 
				
			||||||
			      show_stats);
 | 
								dump_endpoint(vty, endp, trunk->trunk_nr, trunk->trunk_type,
 | 
				
			||||||
		if (i < trunk->number_endpoints - 1)
 | 
									      show_stats);
 | 
				
			||||||
			vty_out(vty, "%s", VTY_NEWLINE);
 | 
								if (i < trunk->number_endpoints - 1)
 | 
				
			||||||
 | 
									vty_out(vty, "%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!llist_empty(&endp->conns))
 | 
				
			||||||
 | 
								active_count++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (active_count == 0)
 | 
				
			||||||
 | 
							vty_out(vty, "No endpoints in use.%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (show_stats)
 | 
						if (show_stats)
 | 
				
			||||||
		dump_ratectr_trunk(vty, trunk);
 | 
							dump_ratectr_trunk(vty, trunk);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SHOW_MGCP_STR "Display information about the MGCP Media Gateway\n"
 | 
					static int mgcp_show(struct vty *vty, int argc, const char **argv,
 | 
				
			||||||
 | 
							     int show_stats, int active_only)
 | 
				
			||||||
DEFUN(show_mcgp, show_mgcp_cmd,
 | 
					 | 
				
			||||||
      "show mgcp [stats]",
 | 
					 | 
				
			||||||
      SHOW_STR
 | 
					 | 
				
			||||||
      SHOW_MGCP_STR
 | 
					 | 
				
			||||||
      "Include Statistics\n")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	int show_stats = argc >= 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
						llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
				
			||||||
		dump_trunk(vty, trunk, show_stats);
 | 
							dump_trunk(vty, trunk, show_stats, active_only);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->osmux)
 | 
						if (g_cfg->osmux)
 | 
				
			||||||
		vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
							vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
				
			||||||
@@ -348,6 +352,27 @@ DEFUN(show_mcgp, show_mgcp_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SHOW_MGCP_STR "Display information about the MGCP Media Gateway\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(show_mgcp, show_mgcp_cmd,
 | 
				
			||||||
 | 
					      "show mgcp [stats]",
 | 
				
			||||||
 | 
					      SHOW_STR
 | 
				
			||||||
 | 
					      SHOW_MGCP_STR
 | 
				
			||||||
 | 
					      "Include statistics\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int show_stats = argc >= 1;
 | 
				
			||||||
 | 
						return mgcp_show(vty, argc, argv, show_stats, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(show_mgcp_active, show_mgcp_active_cmd,
 | 
				
			||||||
 | 
					      "show mgcp active",
 | 
				
			||||||
 | 
					      SHOW_STR
 | 
				
			||||||
 | 
					      SHOW_MGCP_STR
 | 
				
			||||||
 | 
					      "Show only endpoints with active connections\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return mgcp_show(vty, argc, argv, 0, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
dump_mgcp_endpoint(struct vty *vty, struct mgcp_trunk *trunk, const char *epname)
 | 
					dump_mgcp_endpoint(struct vty *vty, struct mgcp_trunk *trunk, const char *epname)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -357,7 +382,7 @@ dump_mgcp_endpoint(struct vty *vty, struct mgcp_trunk *trunk, const char *epname
 | 
				
			|||||||
		/* If a trunk is given, search on that specific trunk only */
 | 
							/* If a trunk is given, search on that specific trunk only */
 | 
				
			||||||
		endp = mgcp_endp_by_name_trunk(NULL, epname, trunk);
 | 
							endp = mgcp_endp_by_name_trunk(NULL, epname, trunk);
 | 
				
			||||||
		if (!endp) {
 | 
							if (!endp) {
 | 
				
			||||||
			vty_out(vty, "endpoint %s not configured on trunk %d%s", epname, trunk->trunk_nr, VTY_NEWLINE);
 | 
								vty_out(vty, "endpoint %s not configured on trunk %u%s", epname, trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -418,7 +443,7 @@ DEFUN_USRATTR(cfg_mgcp_local_ip,
 | 
				
			|||||||
	      "IPv4 Address to use in SDP record\n"
 | 
						      "IPv4 Address to use in SDP record\n"
 | 
				
			||||||
	      "IPv6 Address to use in SDP record\n")
 | 
						      "IPv6 Address to use in SDP record\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->local_ip, argv[0]);
 | 
						osmo_strlcpy(g_cfg->local_ip, argv[0], sizeof(g_cfg->local_ip));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -430,7 +455,7 @@ DEFUN(cfg_mgcp_bind_ip,
 | 
				
			|||||||
      "IPv4 Address to bind to\n"
 | 
					      "IPv4 Address to bind to\n"
 | 
				
			||||||
      "IPv6 Address to bind to\n")
 | 
					      "IPv6 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->source_addr, argv[0]);
 | 
						osmo_strlcpy(g_cfg->source_addr, argv[0], sizeof(g_cfg->source_addr));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -508,7 +533,7 @@ DEFUN_USRATTR(cfg_mgcp_rtp_bind_ip,
 | 
				
			|||||||
	      RTP_STR "Bind endpoints facing the Network\n"
 | 
						      RTP_STR "Bind endpoints facing the Network\n"
 | 
				
			||||||
	      "IPv4 Address to bind to\n")
 | 
						      "IPv4 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->net_ports.bind_addr_v4, argv[0]);
 | 
						osmo_strlcpy(g_cfg->net_ports.bind_addr_v4, argv[0], sizeof(g_cfg->net_ports.bind_addr_v4));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgcp_rtp_bind_ip,
 | 
					ALIAS_DEPRECATED(cfg_mgcp_rtp_bind_ip,
 | 
				
			||||||
@@ -523,8 +548,7 @@ DEFUN_USRATTR(cfg_mgcp_rtp_no_bind_ip,
 | 
				
			|||||||
	      NO_STR RTP_STR "Bind endpoints facing the Network\n"
 | 
						      NO_STR RTP_STR "Bind endpoints facing the Network\n"
 | 
				
			||||||
	      "Address to bind to\n")
 | 
						      "Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	talloc_free(g_cfg->net_ports.bind_addr_v4);
 | 
						osmo_strlcpy(g_cfg->net_ports.bind_addr_v4, "", sizeof(g_cfg->net_ports.bind_addr_v4));
 | 
				
			||||||
	g_cfg->net_ports.bind_addr_v4 = NULL;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgcp_rtp_no_bind_ip,
 | 
					ALIAS_DEPRECATED(cfg_mgcp_rtp_no_bind_ip,
 | 
				
			||||||
@@ -540,7 +564,7 @@ DEFUN_USRATTR(cfg_mgcp_rtp_bind_ip_v6,
 | 
				
			|||||||
	      RTP_STR "Bind endpoints facing the Network\n"
 | 
						      RTP_STR "Bind endpoints facing the Network\n"
 | 
				
			||||||
	      "IPv6 Address to bind to\n")
 | 
						      "IPv6 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->net_ports.bind_addr_v6, argv[0]);
 | 
						osmo_strlcpy(g_cfg->net_ports.bind_addr_v6, argv[0], sizeof(g_cfg->net_ports.bind_addr_v6));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -551,8 +575,7 @@ DEFUN_USRATTR(cfg_mgcp_rtp_no_bind_ip_v6,
 | 
				
			|||||||
	      NO_STR RTP_STR "Bind endpoints facing the Network\n"
 | 
						      NO_STR RTP_STR "Bind endpoints facing the Network\n"
 | 
				
			||||||
	      "Address to bind to\n")
 | 
						      "Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	talloc_free(g_cfg->net_ports.bind_addr_v6);
 | 
						osmo_strlcpy(g_cfg->net_ports.bind_addr_v6, "", sizeof(g_cfg->net_ports.bind_addr_v6));
 | 
				
			||||||
	g_cfg->net_ports.bind_addr_v6 = NULL;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -579,19 +602,27 @@ DEFUN_USRATTR(cfg_mgcp_rtp_no_net_bind_ip_probing,
 | 
				
			|||||||
DEFUN_USRATTR(cfg_mgcp_rtp_ip_dscp,
 | 
					DEFUN_USRATTR(cfg_mgcp_rtp_ip_dscp,
 | 
				
			||||||
	      cfg_mgcp_rtp_ip_dscp_cmd,
 | 
						      cfg_mgcp_rtp_ip_dscp_cmd,
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
	      "rtp ip-dscp <0-255>",
 | 
						      "rtp ip-dscp <0-63>",
 | 
				
			||||||
	      RTP_STR
 | 
						      RTP_STR
 | 
				
			||||||
	      "Apply IP_TOS to the audio stream (including Osmux)\n" "The DSCP value\n")
 | 
						      "Use specified DSCP for the audio stream (including Osmux)\n" "The DSCP value\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int dscp = atoi(argv[0]);
 | 
						int dscp = atoi(argv[0]);
 | 
				
			||||||
	g_cfg->endp_dscp = dscp;
 | 
						g_cfg->endp_dscp = dscp;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd,
 | 
					DEFUN_USRATTR(cfg_mgcp_rtp_priority,
 | 
				
			||||||
		 "rtp ip-tos <0-255>",
 | 
						      cfg_mgcp_rtp_priority_cmd,
 | 
				
			||||||
		 RTP_STR
 | 
						      X(MGW_CMD_ATTR_NEWCONN),
 | 
				
			||||||
		 "Apply IP_TOS to the audio stream\n" "The DSCP value\n")
 | 
						      "rtp socket-priority <0-255>",
 | 
				
			||||||
 | 
						      RTP_STR
 | 
				
			||||||
 | 
						      "socket priority (values > 6 require CAP_NET_ADMIN)\n" "socket priority value\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int prio = atoi(argv[0]);
 | 
				
			||||||
 | 
						g_cfg->endp_priority = prio;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FORCE_PTIME_STR "Force a fixed ptime for packets sent"
 | 
					#define FORCE_PTIME_STR "Force a fixed ptime for packets sent"
 | 
				
			||||||
DEFUN_USRATTR(cfg_mgcp_rtp_force_ptime,
 | 
					DEFUN_USRATTR(cfg_mgcp_rtp_force_ptime,
 | 
				
			||||||
	      cfg_mgcp_rtp_force_ptime_cmd,
 | 
						      cfg_mgcp_rtp_force_ptime_cmd,
 | 
				
			||||||
@@ -917,7 +948,7 @@ DEFUN(cfg_mgcp_agent_addr,
 | 
				
			|||||||
      "IPv4 Address of the call agent\n"
 | 
					      "IPv4 Address of the call agent\n"
 | 
				
			||||||
      "IPv6 Address of the call agent\n")
 | 
					      "IPv6 Address of the call agent\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->call_agent_addr, argv[0]);
 | 
						osmo_strlcpy(g_cfg->call_agent_addr, argv[0], sizeof(g_cfg->call_agent_addr));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -930,7 +961,7 @@ DEFUN(cfg_mgcp_trunk, cfg_mgcp_trunk_cmd,
 | 
				
			|||||||
      "trunk <0-64>", "Configure a SS7 trunk\n" "Trunk Nr\n")
 | 
					      "trunk <0-64>", "Configure a SS7 trunk\n" "Trunk Nr\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	int index = atoi(argv[0]);
 | 
						unsigned int index = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_E1, index);
 | 
						trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_E1, index);
 | 
				
			||||||
	if (!trunk) {
 | 
						if (!trunk) {
 | 
				
			||||||
@@ -962,7 +993,7 @@ static int config_write_trunk(struct vty *vty)
 | 
				
			|||||||
		    && trunk->trunk_nr == MGCP_VIRT_TRUNK_ID)
 | 
							    && trunk->trunk_nr == MGCP_VIRT_TRUNK_ID)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vty_out(vty, " trunk %d%s", trunk->trunk_nr, VTY_NEWLINE);
 | 
							vty_out(vty, " trunk %u%s", trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "  line %u%s", trunk->e1.vty_line_nr, VTY_NEWLINE);
 | 
							vty_out(vty, "  line %u%s", trunk->e1.vty_line_nr, 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);
 | 
				
			||||||
@@ -1302,7 +1333,7 @@ DEFUN(loop_conn,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!trunk->endpoints) {
 | 
						if (!trunk->endpoints) {
 | 
				
			||||||
		vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
 | 
							vty_out(vty, "%%Trunk %u has no endpoints allocated.%s",
 | 
				
			||||||
			trunk->trunk_nr, VTY_NEWLINE);
 | 
								trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1363,7 +1394,7 @@ DEFUN(tap_rtp,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!trunk->endpoints) {
 | 
						if (!trunk->endpoints) {
 | 
				
			||||||
		vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
 | 
							vty_out(vty, "%%Trunk %u has no endpoints allocated.%s",
 | 
				
			||||||
			trunk->trunk_nr, VTY_NEWLINE);
 | 
								trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1430,7 +1461,7 @@ DEFUN(free_endp, free_endp_cmd,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!trunk->endpoints) {
 | 
						if (!trunk->endpoints) {
 | 
				
			||||||
		vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
 | 
							vty_out(vty, "%%Trunk %u has no endpoints allocated.%s",
 | 
				
			||||||
			trunk->trunk_nr, VTY_NEWLINE);
 | 
								trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1463,7 +1494,7 @@ DEFUN(reset_endp, reset_endp_cmd,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!trunk->endpoints) {
 | 
						if (!trunk->endpoints) {
 | 
				
			||||||
		vty_out(vty, "%%Trunk %d has no endpoints allocated.%s",
 | 
							vty_out(vty, "%%Trunk %u has no endpoints allocated.%s",
 | 
				
			||||||
			trunk->trunk_nr, VTY_NEWLINE);
 | 
								trunk->trunk_nr, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1526,7 +1557,7 @@ DEFUN(cfg_mgcp_osmux_ip,
 | 
				
			|||||||
      "IPv4 Address to bind to\n"
 | 
					      "IPv4 Address to bind to\n"
 | 
				
			||||||
      "IPv6 Address to bind to\n")
 | 
					      "IPv6 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->osmux_addr, argv[0]);
 | 
						osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1596,6 +1627,7 @@ DEFUN(cfg_mgcp_conn_timeout,
 | 
				
			|||||||
int mgcp_vty_init(void)
 | 
					int mgcp_vty_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	install_element_ve(&show_mgcp_cmd);
 | 
						install_element_ve(&show_mgcp_cmd);
 | 
				
			||||||
 | 
						install_element_ve(&show_mgcp_active_cmd);
 | 
				
			||||||
	install_element_ve(&show_mgcp_endpoint_cmd);
 | 
						install_element_ve(&show_mgcp_endpoint_cmd);
 | 
				
			||||||
	install_element_ve(&show_mgcp_trunk_endpoint_cmd);
 | 
						install_element_ve(&show_mgcp_trunk_endpoint_cmd);
 | 
				
			||||||
	install_element(ENABLE_NODE, &loop_conn_cmd);
 | 
						install_element(ENABLE_NODE, &loop_conn_cmd);
 | 
				
			||||||
@@ -1622,7 +1654,7 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_probing_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_net_bind_ip_probing_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_probing_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_no_net_bind_ip_probing_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_priority_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
 | 
				
			||||||
@@ -1714,7 +1746,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!g_cfg->source_addr) {
 | 
						if (!strlen(g_cfg->source_addr)) {
 | 
				
			||||||
		fprintf(stderr, "You need to specify a bind address.\n");
 | 
							fprintf(stderr, "You need to specify a bind address.\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1722,7 +1754,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			|||||||
	llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
 | 
						llist_for_each_entry(trunk, &g_cfg->trunks, entry) {
 | 
				
			||||||
		if (mgcp_trunk_equip(trunk) != 0) {
 | 
							if (mgcp_trunk_equip(trunk) != 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "Failed to initialize trunk %d (%d endpoints)\n",
 | 
								     "Failed to initialize trunk %u (%d endpoints)\n",
 | 
				
			||||||
			     trunk->trunk_nr, trunk->number_endpoints);
 | 
								     trunk->trunk_nr, trunk->number_endpoints);
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -235,7 +235,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
	/* reset endpoints */
 | 
						/* reset endpoints */
 | 
				
			||||||
	if (reset_endpoints) {
 | 
						if (reset_endpoints) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE,
 | 
							LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		     "Asked to reset endpoints: %d/%d\n",
 | 
							     "Asked to reset endpoints: %u/%d\n",
 | 
				
			||||||
		     reset_trunk->trunk_nr, reset_trunk->trunk_type);
 | 
							     reset_trunk->trunk_nr, reset_trunk->trunk_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* reset flag */
 | 
							/* reset flag */
 | 
				
			||||||
@@ -243,7 +243,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* Walk over all endpoints and trigger a release, this will release all
 | 
							/* Walk over all endpoints and trigger a release, this will release all
 | 
				
			||||||
		 * endpoints, possible open connections are forcefully dropped */
 | 
							 * endpoints, possible open connections are forcefully dropped */
 | 
				
			||||||
		for (i = 1; i < reset_trunk->number_endpoints; ++i)
 | 
							for (i = 0; i < reset_trunk->number_endpoints; ++i)
 | 
				
			||||||
			mgcp_endp_release(reset_trunk->endpoints[i]);
 | 
								mgcp_endp_release(reset_trunk->endpoints[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -369,12 +369,12 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* we need to bind a socket */
 | 
						/* we need to bind a socket */
 | 
				
			||||||
	flags = OSMO_SOCK_F_BIND;
 | 
						flags = OSMO_SOCK_F_BIND;
 | 
				
			||||||
	if (cfg->call_agent_addr)
 | 
						if (strlen(cfg->call_agent_addr))
 | 
				
			||||||
		flags |= OSMO_SOCK_F_CONNECT;
 | 
							flags |= OSMO_SOCK_F_CONNECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
 | 
						rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
 | 
				
			||||||
				cfg->source_addr, cfg->source_port,
 | 
									cfg->source_addr, cfg->source_port,
 | 
				
			||||||
				cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
 | 
									cfg->call_agent_addr, strlen(cfg->call_agent_addr) ? 2727 : 0, flags);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		perror("Gateway failed to bind");
 | 
							perror("Gateway failed to bind");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ EXTRA_DIST = \
 | 
				
			|||||||
	mgcp_test.ok \
 | 
						mgcp_test.ok \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = \
 | 
					check_PROGRAMS = \
 | 
				
			||||||
	mgcp_test \
 | 
						mgcp_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
@@ -127,7 +128,7 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=fmtp:126 0/1/2\r\n" \
 | 
						"a=fmtp:126 0/1/2\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4 \
 | 
					#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" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
@@ -142,6 +143,24 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MDCX4_ADDR0000_RET \
 | 
				
			||||||
 | 
						"527 18983216 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MDCX4 \
 | 
				
			||||||
 | 
						"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
 | 
						"M: sendrecv\r" \
 | 
				
			||||||
 | 
						"C: 2\r\n" \
 | 
				
			||||||
 | 
						"I: %s\r\n" \
 | 
				
			||||||
 | 
						"L: p:20, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
 | 
						"\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 5.6.7.8\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RET(Ident) \
 | 
					#define MDCX4_RET(Ident) \
 | 
				
			||||||
	"200 " Ident " OK\r\n" \
 | 
						"200 " Ident " OK\r\n" \
 | 
				
			||||||
	"\r\n" \
 | 
						"\r\n" \
 | 
				
			||||||
@@ -167,45 +186,45 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT1 \
 | 
					#define MDCX4_PT1 \
 | 
				
			||||||
	"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: SENDRECV\r" \
 | 
						"M: SENDRECV\r" \
 | 
				
			||||||
	"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" \
 | 
						"\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 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\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:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT2 \
 | 
					#define MDCX4_PT2 \
 | 
				
			||||||
	"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r" \
 | 
				
			||||||
	"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" \
 | 
						"\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 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\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:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT3 \
 | 
					#define MDCX4_PT3 \
 | 
				
			||||||
	"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: sendrecv\r" \
 | 
				
			||||||
	"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" \
 | 
						"\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 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\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" \
 | 
				
			||||||
@@ -213,47 +232,47 @@ static void test_strline(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Test different upper/lower case in options */
 | 
					/* Test different upper/lower case in options */
 | 
				
			||||||
#define MDCX4_PT4 \
 | 
					#define MDCX4_PT4 \
 | 
				
			||||||
	"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"m: sendrecv\r" \
 | 
						"m: sendrecv\r" \
 | 
				
			||||||
	"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" \
 | 
						"\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 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\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:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_SO \
 | 
					#define MDCX4_SO \
 | 
				
			||||||
	"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendonly\r" \
 | 
						"M: sendonly\r" \
 | 
				
			||||||
	"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" \
 | 
						"\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 5.6.7.8\r\n" \
 | 
				
			||||||
	"c=IN IP4 0.0.0.0\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:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RO \
 | 
					#define MDCX4_RO \
 | 
				
			||||||
	"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: recvonly\r" \
 | 
						"M: recvonly\r" \
 | 
				
			||||||
	"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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX_TOO_LONG_CI \
 | 
					#define MDCX_TOO_LONG_CI \
 | 
				
			||||||
	"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983224 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"I: 123456789012345678901234567890123\n"
 | 
						"I: 123456789012345678901234567890123\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX_TOO_LONG_CI_RET "510 18983223 FAIL\r\n"
 | 
					#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SHORT2	"CRCX 1"
 | 
					#define SHORT2	"CRCX 1"
 | 
				
			||||||
#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
					#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
				
			||||||
@@ -541,13 +560,14 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
 | 
						{"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
 | 
				
			||||||
	{"CRCX", CRCX, CRCX_RET, 97},
 | 
						{"CRCX", CRCX, CRCX_RET, 97},
 | 
				
			||||||
	{"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
 | 
						{"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
 | 
				
			||||||
	{"MDCX4", MDCX4, MDCX4_RET("18983216"), 99},
 | 
						{"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
 | 
				
			||||||
	{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
 | 
						{"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
 | 
				
			||||||
	{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
 | 
						{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
 | 
				
			||||||
	{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
 | 
						{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
 | 
				
			||||||
	{"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983220"), 99},
 | 
						{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
 | 
				
			||||||
	{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983221"), 99},
 | 
						{"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
 | 
				
			||||||
	{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983222"), PTYPE_IGNORE},
 | 
						{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
 | 
				
			||||||
 | 
						{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
 | 
				
			||||||
	{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
						{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
				
			||||||
	{"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
 | 
						{"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
 | 
				
			||||||
	{"EMPTY", EMPTY, EMPTY_RET},
 | 
						{"EMPTY", EMPTY, EMPTY_RET},
 | 
				
			||||||
@@ -594,29 +614,6 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char last_endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int mgcp_test_policy_cb(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
			       int state, const char *transaction_id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fprintf(stderr, "Policy CB got state %d on endpoint %s\n",
 | 
					 | 
				
			||||||
		state, endp->name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	trunk = endp->trunk;
 | 
					 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
					 | 
				
			||||||
	for (i = 0; i < trunk->number_endpoints; i++) {
 | 
					 | 
				
			||||||
		if (strcmp(endp->name, trunk->endpoints[i]->name) == 0)
 | 
					 | 
				
			||||||
			osmo_strlcpy(last_endpoint, trunk->endpoints[i]->name,
 | 
					 | 
				
			||||||
				     sizeof(last_endpoint));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return MGCP_POLICY_CONT;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					 | 
				
			||||||
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,
 | 
					ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 | 
				
			||||||
@@ -626,13 +623,18 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 | 
				
			|||||||
	    htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
 | 
						    htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
 | 
				
			||||||
	int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
 | 
						int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len == 1 && ((const char *)buf)[0] == MGCP_DUMMY_LOAD) {
 | 
						if (len == sizeof(rtp_dummy_payload)
 | 
				
			||||||
 | 
						    && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
 | 
				
			||||||
		fprintf(stderr,
 | 
							fprintf(stderr,
 | 
				
			||||||
			"Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
 | 
								"Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
 | 
				
			||||||
			dest_host, dest_port, len, osmo_hexdump(buf, len));
 | 
								dest_host, dest_port, len, osmo_hexdump(buf, len));
 | 
				
			||||||
		dummy_packets += 1;
 | 
							dummy_packets += 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure address+port are valid */
 | 
				
			||||||
 | 
						OSMO_ASSERT(dest_host);
 | 
				
			||||||
 | 
						OSMO_ASSERT(dest_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return len;
 | 
						return len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -768,13 +770,13 @@ static void test_messages(void)
 | 
				
			|||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
	char last_conn_id[256];
 | 
						char last_conn_id[256];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						char *last_endpoint = mgcp_debug_get_last_endpoint_name();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
	trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk->v.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
        mgcp_trunk_equip(trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
						memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -786,7 +788,6 @@ static void test_messages(void)
 | 
				
			|||||||
		printf("\n================================================\n");
 | 
							printf("\n================================================\n");
 | 
				
			||||||
		printf("Testing %s\n", t->name);
 | 
							printf("Testing %s\n", t->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		last_endpoint[0] = '\0';
 | 
					 | 
				
			||||||
		dummy_packets = 0;
 | 
							dummy_packets = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
 | 
							osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
 | 
				
			||||||
@@ -867,7 +868,7 @@ static void test_messages(void)
 | 
				
			|||||||
					printf("Connection mode not set\n");
 | 
										printf("Connection mode not set\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				OSMO_ASSERT(conn->end.output_enabled
 | 
									OSMO_ASSERT(conn->end.output_enabled
 | 
				
			||||||
					    == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
 | 
										    == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				conn->conn->mode |= CONN_UNMODIFIED;
 | 
									conn->conn->mode |= CONN_UNMODIFIED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -959,7 +960,7 @@ static void test_retransmission(void)
 | 
				
			|||||||
static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
 | 
					static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ptrdiff_t tone = _tone;
 | 
						ptrdiff_t tone = _tone;
 | 
				
			||||||
	endp->cfg->data = (void *)tone;
 | 
						endp->trunk->cfg->data = (void *)tone;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1041,20 +1042,19 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
	struct mgcp_endpoint *endpoints[1];
 | 
						struct mgcp_endpoint *endpoints[1];
 | 
				
			||||||
	struct mgcp_config cfg = {0};
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_trunk trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing packet loss calculation.\n");
 | 
						printf("Testing packet loss calculation.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&endp, 0, sizeof(endp));
 | 
						memset(&endp, 0, sizeof(endp));
 | 
				
			||||||
	memset(&trunk, 0, sizeof(trunk));
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	endp.cfg = &cfg;
 | 
					 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
	trunk.v.vty_number_endpoints = 1;
 | 
						trunk->v.vty_number_endpoints = 1;
 | 
				
			||||||
	trunk.endpoints = endpoints;
 | 
						trunk->endpoints = endpoints;
 | 
				
			||||||
	trunk.endpoints[0] = &endp;
 | 
						trunk->endpoints[0] = &endp;
 | 
				
			||||||
	endp.trunk = &trunk;
 | 
						endp.trunk = trunk;
 | 
				
			||||||
	INIT_LLIST_HEAD(&endp.conns);
 | 
						INIT_LLIST_HEAD(&endp.conns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
 | 
				
			||||||
@@ -1071,7 +1071,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
				    "test-connection");
 | 
									    "test-connection");
 | 
				
			||||||
		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
							conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
				
			||||||
		state = &conn->state;
 | 
							state = &conn->state;
 | 
				
			||||||
		packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
 | 
							packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->stats.initialized = 1;
 | 
							state->stats.initialized = 1;
 | 
				
			||||||
		state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
							state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
				
			||||||
@@ -1092,6 +1092,8 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
		mgcp_conn_free_all(&endp);
 | 
							mgcp_conn_free_all(&endp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(trunk);
 | 
				
			||||||
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
 | 
					int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
 | 
				
			||||||
@@ -1258,21 +1260,25 @@ struct rtp_packet_info test_rtp_packets1[] = {
 | 
				
			|||||||
	/* RTP: SeqNo=1002, TS=160320 */
 | 
						/* RTP: SeqNo=1002, TS=160320 */
 | 
				
			||||||
	{2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
 | 
						{2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
 | 
				
			||||||
	 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
 | 
						 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
 | 
				
			||||||
 | 
						/* RTP: SeqNo=1003, TS=180320, Marker */
 | 
				
			||||||
 | 
						{2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
 | 
				
			||||||
 | 
						 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
 | 
				
			||||||
 | 
						 /* RTP: SeqNo=1004, TS=180480 */
 | 
				
			||||||
 | 
						{2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
 | 
				
			||||||
 | 
						 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
 | 
				
			||||||
 | 
						 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
 | 
				
			||||||
 | 
						{2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
 | 
				
			||||||
 | 
						 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
			  struct mgcp_rtp_state *state,
 | 
					 | 
				
			||||||
			  struct mgcp_rtp_end *rtp_end,
 | 
					 | 
				
			||||||
			  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
					static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mgcp_trunk trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
	struct mgcp_endpoint *endpoints[1];
 | 
						struct mgcp_endpoint *endpoints[1];
 | 
				
			||||||
	struct mgcp_config cfg = {0};
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_rtp_state state;
 | 
						struct mgcp_rtp_state state;
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
	struct osmo_sockaddr addr = { 0 };
 | 
						struct osmo_sockaddr addr = { 0 };
 | 
				
			||||||
@@ -1290,7 +1296,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	       patch_ssrc ? ", patch SSRC" : "",
 | 
						       patch_ssrc ? ", patch SSRC" : "",
 | 
				
			||||||
	       patch_ts ? ", patch timestamps" : "");
 | 
						       patch_ts ? ", patch timestamps" : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&trunk, 0, sizeof(trunk));
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	memset(&endp, 0, sizeof(endp));
 | 
						memset(&endp, 0, sizeof(endp));
 | 
				
			||||||
	memset(&state, 0, sizeof(state));
 | 
						memset(&state, 0, sizeof(state));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1299,16 +1306,15 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	state.in_stream.err_ts_ctr = &test_ctr_in;
 | 
						state.in_stream.err_ts_ctr = &test_ctr_in;
 | 
				
			||||||
	state.out_stream.err_ts_ctr = &test_ctr_out;
 | 
						state.out_stream.err_ts_ctr = &test_ctr_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endp.cfg = &cfg;
 | 
					 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk.v.vty_number_endpoints = 1;
 | 
						trunk->v.vty_number_endpoints = 1;
 | 
				
			||||||
	trunk.endpoints = endpoints;
 | 
						trunk->endpoints = endpoints;
 | 
				
			||||||
	trunk.endpoints[0] = &endp;
 | 
						trunk->endpoints[0] = &endp;
 | 
				
			||||||
	trunk.force_constant_ssrc = patch_ssrc;
 | 
						trunk->force_constant_ssrc = patch_ssrc;
 | 
				
			||||||
	trunk.force_aligned_timing = patch_ts;
 | 
						trunk->force_aligned_timing = patch_ts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endp.trunk = &trunk;
 | 
						endp.trunk = trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&endp.conns);
 | 
						INIT_LLIST_HEAD(&endp.conns);
 | 
				
			||||||
	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
						_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
@@ -1367,6 +1373,8 @@ 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_conn_free_all(&endp);
 | 
				
			||||||
 | 
						talloc_free(trunk);
 | 
				
			||||||
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_multilple_codec(void)
 | 
					static void test_multilple_codec(void)
 | 
				
			||||||
@@ -1378,6 +1386,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	struct in_addr addr;
 | 
						struct in_addr addr;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
	char conn_id[256];
 | 
						char conn_id[256];
 | 
				
			||||||
 | 
						char *last_endpoint = mgcp_debug_get_last_endpoint_name();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing multiple payload types\n");
 | 
						printf("Testing multiple payload types\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1385,7 +1394,6 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	trunk->v.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
        mgcp_trunk_equip(trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate endpoint 1@mgw with two codecs */
 | 
						/* Allocate endpoint 1@mgw with two codecs */
 | 
				
			||||||
	last_endpoint[0] = '\0';
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
@@ -1547,24 +1555,24 @@ static void test_no_cycle(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 0);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
 | 
						mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
						OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
						OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
 | 
						mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
						OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.max_seq == 1);
 | 
						OSMO_ASSERT(conn->state.stats.max_seq == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* now jump.. */
 | 
						/* now jump.. */
 | 
				
			||||||
	mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
 | 
						mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
						OSMO_ASSERT(conn->state.stats.cycles == 0);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
 | 
						OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* and wrap */
 | 
						/* and wrap */
 | 
				
			||||||
	mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
 | 
						mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
						OSMO_ASSERT(conn->state.stats.initialized == 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
 | 
						OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
						OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
				
			||||||
@@ -1587,8 +1595,6 @@ static void test_no_name(void)
 | 
				
			|||||||
	trunk->audio_send_name = 0;
 | 
						trunk->audio_send_name = 0;
 | 
				
			||||||
        mgcp_trunk_equip(trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inp = create_msg(CRCX, NULL);
 | 
						inp = create_msg(CRCX, NULL);
 | 
				
			||||||
	msg = mgcp_handle_message(cfg, inp);
 | 
						msg = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1890,16 +1896,13 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
				{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 121}, },
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
					 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -1908,15 +1911,13 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, -EINVAL}, },
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
					 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -1925,15 +1926,13 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
				{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", NULL, },
 | 
									{ 122, "AMR/8000", NULL, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, -EINVAL}, },
 | 
								{ .payload_type_map = {111, 122}, },
 | 
				
			||||||
			{ .payload_type_map = {112, 122} },
 | 
					 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -2121,46 +2120,95 @@ void test_conn_id_matching()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void test_e1_trunk_nr_from_epname()
 | 
					void test_e1_trunk_nr_from_epname()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: e1_trunk_nr_from_epname does not check the text
 | 
						/* Note: e1_trunk_nr_from_epname does not check the text
 | 
				
			||||||
	 * after the E1 trunk number, after the delimiter
 | 
						 * after the E1 trunk number, after the delimiter
 | 
				
			||||||
	 * character "/" arbitrary text may follow. */
 | 
						 * character "/" arbitrary text may follow. */
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 0);
 | 
						OSMO_ASSERT(trunk_nr == 0);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 1);
 | 
						OSMO_ASSERT(trunk_nr == 1);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 2);
 | 
						OSMO_ASSERT(trunk_nr == 2);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 3);
 | 
						OSMO_ASSERT(trunk_nr == 3);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 3);
 | 
						OSMO_ASSERT(trunk_nr == 3);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 24);
 | 
						OSMO_ASSERT(trunk_nr == 24);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == 64);
 | 
						OSMO_ASSERT(trunk_nr == 64);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The following endpoint strings should fail, either the
 | 
						/* The following endpoint strings should fail, either the
 | 
				
			||||||
	 * trunk number exceeds the valid range or the trunk prefix
 | 
						 * trunk number exceeds the valid range or the trunk prefix
 | 
				
			||||||
	 * is wrong. Also when the delimiter character "/" at the
 | 
						 * is wrong. Also when the delimiter character "/" at the
 | 
				
			||||||
	 * end of the trunk is wrong the parsing should fail. */
 | 
						 * end of the trunk is wrong the parsing should fail. */
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
	trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
 | 
						rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
 | 
				
			||||||
	OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
						OSMO_ASSERT(rc == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_mgcp_is_rtp_dummy_payload()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* realistic rtp packet */
 | 
				
			||||||
 | 
						static const char rtp_payload[] =
 | 
				
			||||||
 | 
						    { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
 | 
				
			||||||
 | 
						      0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
 | 
				
			||||||
 | 
						      0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
 | 
				
			||||||
 | 
						      0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
 | 
				
			||||||
 | 
						      0x24 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
 | 
				
			||||||
 | 
						struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
 | 
				
			||||||
 | 
						struct msgb *msg_dummy_rtp =
 | 
				
			||||||
 | 
						    msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t *buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Dummy RTP packet */
 | 
				
			||||||
 | 
						buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
 | 
				
			||||||
 | 
						memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Normal RTP packet */
 | 
				
			||||||
 | 
						buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
 | 
				
			||||||
 | 
						memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Dummy RTP packet with normal RTP packet attached, this must not be
 | 
				
			||||||
 | 
						 * recognized as Dummy RTP packet */
 | 
				
			||||||
 | 
						buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
 | 
				
			||||||
 | 
						memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
 | 
				
			||||||
 | 
						buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
 | 
				
			||||||
 | 
						memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
 | 
				
			||||||
 | 
						OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
 | 
				
			||||||
 | 
						OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(msg_dummy);
 | 
				
			||||||
 | 
						msgb_free(msg_rtp);
 | 
				
			||||||
 | 
						msgb_free(msg_dummy_rtp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
 | 
						void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
 | 
				
			||||||
@@ -2187,6 +2235,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_mgcp_codec_pt_translate();
 | 
						test_mgcp_codec_pt_translate();
 | 
				
			||||||
	test_conn_id_matching();
 | 
						test_conn_id_matching();
 | 
				
			||||||
	test_e1_trunk_nr_from_epname();
 | 
						test_e1_trunk_nr_from_epname();
 | 
				
			||||||
 | 
						test_mgcp_is_rtp_dummy_payload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
 | 
						OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
 | 
				
			||||||
	OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
 | 
						OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,7 +97,7 @@ Response matches our expectations.
 | 
				
			|||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4
 | 
					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
 | 
				
			||||||
@@ -113,6 +113,29 @@ m=audio 4441 RTP/AVP 99
 | 
				
			|||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing MDCX4
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					MDCX 18983217 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					I: %s
 | 
				
			||||||
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
 | 
					t=0 0
 | 
				
			||||||
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
@@ -124,14 +147,14 @@ Dummy packets: 2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_PT1
 | 
					Testing MDCX4_PT1
 | 
				
			||||||
---------8<---------
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983218 1@mgw MGCP 1.0
 | 
					MDCX 18983218 1@mgw MGCP 1.0
 | 
				
			||||||
M: SENDRECV
 | 
					M: SENDRECV
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
 | 
					L: p:20-40, a:AMR, nt:IN
 | 
				
			||||||
v=0
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
o=- %s 23 IN IP4 5.6.7.8
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
c=IN IP4 5.6.7.8
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
@@ -148,14 +171,14 @@ Dummy packets: 2
 | 
				
			|||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
creating message from statically defined input:
 | 
					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
 | 
				
			||||||
M: sendrecv
 | 
					M: sendrecv
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
L: p:20-20, a:AMR, nt:IN
 | 
					I: %s
 | 
				
			||||||
 | 
					L: p:20-20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
o=- %s 23 IN IP4 5.6.7.8
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
@@ -172,14 +195,14 @@ Dummy packets: 2
 | 
				
			|||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing MDCX4_PT3
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_PT3
 | 
					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
 | 
				
			||||||
M: sendrecv
 | 
					M: sendrecv
 | 
				
			||||||
I: %s
 | 
					C: 2
 | 
				
			||||||
L: a:AMR, nt:IN
 | 
					I: %s
 | 
				
			||||||
L: a:AMR, nt:IN
 | 
					L: a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
@@ -196,14 +219,14 @@ Dummy packets: 2
 | 
				
			|||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
================================================
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_PT4
 | 
					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
 | 
				
			||||||
c: 2
 | 
					m: sendrecv
 | 
				
			||||||
i: %s
 | 
					c: 2
 | 
				
			||||||
i: %s
 | 
					i: %s
 | 
				
			||||||
l: A:amr, NT:IN
 | 
					l: A:amr, NT:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -220,14 +243,14 @@ Dummy packets: 2
 | 
				
			|||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_SO
 | 
					Testing MDCX4_SO
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
M: sendonly
 | 
					MDCX 18983222 1@mgw MGCP 1.0
 | 
				
			||||||
C: 2
 | 
					M: sendonly
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
@@ -243,7 +266,7 @@ Response matches our expectations.
 | 
				
			|||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
(response contains a connection id)
 | 
					Response matches our expectations.
 | 
				
			||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
@@ -441,7 +464,6 @@ checking response:
 | 
				
			|||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response does not contain a connection id)
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing CRCX
 | 
					 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing CRCX
 | 
					Testing CRCX
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -470,7 +492,7 @@ Dummy packets: 2
 | 
				
			|||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -770,6 +792,15 @@ Stats: Jitter = 0, Transit = -144000
 | 
				
			|||||||
Stats: Jitter = 24, Transit = -32888
 | 
					Stats: Jitter = 24, Transit = -32888
 | 
				
			||||||
In TS: 36728, dTS: 160, Seq: 24
 | 
					In TS: 36728, dTS: 160, Seq: 24
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 22, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 36888, dTS: 160, Seq: 25
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 21, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 160000, dTS: 0, Seq: 1000
 | 
				
			||||||
 | 
					Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 160160, dTS: 160, Seq: 1001
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
In TS: 160320, dTS: 160, Seq: 1002
 | 
					In TS: 160320, dTS: 160, Seq: 1002
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
@@ -864,6 +895,15 @@ Stats: Jitter = 0, Transit = -144000
 | 
				
			|||||||
In TS: 36728, dTS: 160, Seq: 24
 | 
					In TS: 36728, dTS: 160, Seq: 24
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 22, Transit = -32888
 | 
					Stats: Jitter = 22, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 36888, dTS: 160, Seq: 25
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 21, Transit = -32888
 | 
				
			||||||
 | 
					Output SSRC changed to 50607080
 | 
				
			||||||
 | 
					In TS: 160000, dTS: 0, Seq: 1000
 | 
				
			||||||
 | 
					Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 160160, dTS: 160, Seq: 1001
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
In TS: 160320, dTS: 160, Seq: 1002
 | 
					In TS: 160320, dTS: 160, Seq: 1002
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
@@ -958,6 +998,15 @@ Stats: Jitter = 0, Transit = -144000
 | 
				
			|||||||
In TS: 36728, dTS: 160, Seq: 24
 | 
					In TS: 36728, dTS: 160, Seq: 24
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 22, Transit = -32888
 | 
					Stats: Jitter = 22, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 36888, dTS: 160, Seq: 25
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 21, Transit = -32888
 | 
				
			||||||
 | 
					Output SSRC changed to 50607080
 | 
				
			||||||
 | 
					In TS: 160000, dTS: 0, Seq: 1000
 | 
				
			||||||
 | 
					Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 160160, dTS: 160, Seq: 1001
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
In TS: 160320, dTS: 160, Seq: 1002
 | 
					In TS: 160320, dTS: 160, Seq: 1002
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
@@ -1050,6 +1099,15 @@ Stats: Jitter = 0, Transit = -144000
 | 
				
			|||||||
Stats: Jitter = 24, Transit = -32888
 | 
					Stats: Jitter = 24, Transit = -32888
 | 
				
			||||||
In TS: 36728, dTS: 160, Seq: 24
 | 
					In TS: 36728, dTS: 160, Seq: 24
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 22, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 36888, dTS: 160, Seq: 25
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 21, Transit = -32888
 | 
				
			||||||
 | 
					In TS: 160000, dTS: 0, Seq: 1000
 | 
				
			||||||
 | 
					Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 160160, dTS: 160, Seq: 1001
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
In TS: 160320, dTS: 160, Seq: 1002
 | 
					In TS: 160320, dTS: 160, Seq: 1002
 | 
				
			||||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
@@ -1289,32 +1347,24 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 | 
				
			||||||
#4: conn1 has no codecs
 | 
					#4: conn1 has no codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    (none)
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 | 
				
			||||||
    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    (none)
 | 
					    (none)
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
					#5: test AMR with differing octet-aligned settings
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 121
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
					 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 122
 | 
				
			||||||
    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
 | 
				
			||||||
 - add codecs on conn1:
 | 
					#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ EXTRA_DIST = \
 | 
				
			|||||||
	mgcp_client_test.err \
 | 
						mgcp_client_test.err \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = \
 | 
					check_PROGRAMS = \
 | 
				
			||||||
	mgcp_client_test \
 | 
						mgcp_client_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,19 @@
 | 
				
			|||||||
DLMGCP MGCP client: using endpoint domain '@mgw'
 | 
					DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
DLMGCP message buffer to small, can not generate MGCP message
 | 
					DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_mgcp_client_cancel():
 | 
					test_mgcp_client_cancel():
 | 
				
			||||||
DLMGCP MGCP client: using endpoint domain '@mgw'
 | 
					DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
- composed msg with trans_id=1
 | 
					- composed msg with trans_id=1
 | 
				
			||||||
- not in queue yet, cannot cancel yet
 | 
					- not in queue yet, cannot cancel yet
 | 
				
			||||||
DLMGCP Cannot cancel, no such transaction: 1
 | 
					DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
 | 
				
			||||||
- enqueue
 | 
					- enqueue
 | 
				
			||||||
- cancel succeeds
 | 
					- cancel succeeds
 | 
				
			||||||
DLMGCP Canceled transaction 1
 | 
					DLMGCP MGW(mgw) Canceled transaction 1
 | 
				
			||||||
- late response gets discarded
 | 
					- late response gets discarded
 | 
				
			||||||
DLMGCP Cannot find matching MGCP transaction for trans_id 1
 | 
					DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
 | 
				
			||||||
 | 
					DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
 | 
				
			||||||
- canceling again does nothing
 | 
					- canceling again does nothing
 | 
				
			||||||
DLMGCP Cannot cancel, no such transaction: 1
 | 
					DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
 | 
				
			||||||
test_mgcp_client_cancel() done
 | 
					test_mgcp_client_cancel() done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [0]:
 | 
					test_sdp_section_start() test [0]:
 | 
				
			||||||
@@ -129,9 +130,9 @@ DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
				
			|||||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
					DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
					DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
					DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
				
			||||||
DLMGCP MGCP client: using endpoint domain '@mgw'
 | 
					DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
 | 
					DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
 | 
				
			||||||
DLMGCP 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 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 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!
 | 
				
			||||||
Done
 | 
					Done
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user