mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			394 Commits
		
	
	
		
			2021q1
			...
			rhizomatic
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4dde3b6873 | ||
| 
						 | 
					43279942c3 | ||
| 
						 | 
					2eacae8f2e | ||
| 
						 | 
					403d5f1489 | ||
| 
						 | 
					f227633959 | ||
| 
						 | 
					83c8846728 | ||
| 
						 | 
					78ee99adcf | ||
| 
						 | 
					de4090d920 | ||
| 
						 | 
					732cadd2c8 | ||
| 
						 | 
					6747b60a95 | ||
| 
						 | 
					90ae9ed0a2 | ||
| 
						 | 
					206be49c69 | ||
| 
						 | 
					45559e9230 | ||
| 
						 | 
					f94b846224 | ||
| 
						 | 
					3ea3a69821 | ||
| 
						 | 
					46ddc65626 | ||
| 
						 | 
					71f313749e | ||
| 
						 | 
					80a5abbbe3 | ||
| 
						 | 
					ba812f7e86 | ||
| 
						 | 
					345c37a543 | ||
| 
						 | 
					b3457cd250 | ||
| 
						 | 
					fcf1864db3 | ||
| 
						 | 
					9221b67f3b | ||
| 
						 | 
					732d595a26 | ||
| 
						 | 
					3bc9d53628 | ||
| 
						 | 
					b5a4f45dbf | ||
| 
						 | 
					e6bafbf3e3 | ||
| 
						 | 
					5c7b128166 | ||
| 
						 | 
					5469edc278 | ||
| 
						 | 
					66952183a9 | ||
| 
						 | 
					cc97f58d96 | ||
| 
						 | 
					5d6931881a | ||
| 
						 | 
					0f4be7699b | ||
| 
						 | 
					546983cdbc | ||
| 
						 | 
					c04de4e7bb | ||
| 
						 | 
					d46cdd80de | ||
| 
						 | 
					6676e63c89 | ||
| 
						 | 
					1f99c3aaae | ||
| 
						 | 
					e6ef4e7484 | ||
| 
						 | 
					b0fa041a28 | ||
| 
						 | 
					e17bf77bdd | ||
| 
						 | 
					802b1fad61 | ||
| 
						 | 
					8a8973eec2 | ||
| 
						 | 
					17e7ea66e4 | ||
| 
						 | 
					9c3fad2c42 | ||
| 
						 | 
					227a800d26 | ||
| 
						 | 
					24cae67f3e | ||
| 
						 | 
					0d47c408ac | ||
| 
						 | 
					f1b557988d | ||
| 
						 | 
					95e504aa97 | ||
| 
						 | 
					a5ae091fdd | ||
| 
						 | 
					249f799a88 | ||
| 
						 | 
					dc395843ff | ||
| 
						 | 
					c5d003e09e | ||
| 
						 | 
					e6398d886b | ||
| 
						 | 
					23140d6f94 | ||
| 
						 | 
					36c823eef1 | ||
| 
						 | 
					fa393fa1e9 | ||
| 
						 | 
					e0fc37a437 | ||
| 
						 | 
					4aa2b0e35b | ||
| 
						 | 
					e01f6e7f33 | ||
| 
						 | 
					388b48d14e | ||
| 
						 | 
					352b967d1b | ||
| 
						 | 
					ed4da25f2f | ||
| 
						 | 
					5abda312ed | ||
| 
						 | 
					75862d3131 | ||
| 
						 | 
					8733542b13 | ||
| 
						 | 
					d7aac20cc1 | ||
| 
						 | 
					8b5361412c | ||
| 
						 | 
					3a971ba0d1 | ||
| 
						 | 
					c4b90354ca | ||
| 
						 | 
					28fd236044 | ||
| 
						 | 
					17b5701f19 | ||
| 
						 | 
					9bea6eb78c | ||
| 
						 | 
					fd57bd5f6f | ||
| 
						 | 
					d0dbda4106 | ||
| 
						 | 
					35a738214c | ||
| 
						 | 
					afbe872045 | ||
| 
						 | 
					909be19285 | ||
| 
						 | 
					8ee08c6b78 | ||
| 
						 | 
					c053e07336 | ||
| 
						 | 
					2b30cbdfa8 | ||
| 
						 | 
					c9df010416 | ||
| 
						 | 
					3a3e1b57c6 | ||
| 
						 | 
					186d4f1a0b | ||
| 
						 | 
					cc2f7937ed | ||
| 
						 | 
					960c031a67 | ||
| 
						 | 
					4993452561 | ||
| 
						 | 
					43eed63b09 | ||
| 
						 | 
					7a6d9c2f72 | ||
| 
						 | 
					f3715dc0d3 | ||
| 
						 | 
					a68a863b9d | ||
| 
						 | 
					18717f5247 | ||
| 
						 | 
					677b5396cb | ||
| 
						 | 
					5d0e07112f | ||
| 
						 | 
					a5acaa68db | ||
| 
						 | 
					7787a3aeae | ||
| 
						 | 
					dd1ddf74fc | ||
| 
						 | 
					5e101c9fed | ||
| 
						 | 
					f6db465082 | ||
| 
						 | 
					a7e6fbc220 | ||
| 
						 | 
					cd132126ef | ||
| 
						 | 
					249d21eb1e | ||
| 
						 | 
					0127a0608d | ||
| 
						 | 
					8b663e4d7c | ||
| 
						 | 
					5e5c7bc176 | ||
| 
						 | 
					c695e9f972 | ||
| 
						 | 
					2bdad960ff | ||
| 
						 | 
					58d5b97831 | ||
| 
						 | 
					6225b5cecb | ||
| 
						 | 
					c415ed5113 | ||
| 
						 | 
					730a1f28d2 | ||
| 
						 | 
					af67178581 | ||
| 
						 | 
					dc7dfd0bbd | ||
| 
						 | 
					c364f4ab5a | ||
| 
						 | 
					e9989b9e76 | ||
| 
						 | 
					9423817311 | ||
| 
						 | 
					292ba1bdb1 | ||
| 
						 | 
					10d9f8dcf4 | ||
| 
						 | 
					4c0658955e | ||
| 
						 | 
					e9164c295d | ||
| 
						 | 
					563386e8bb | ||
| 
						 | 
					af0f58fac7 | ||
| 
						 | 
					2e411f33a0 | ||
| 
						 | 
					8e8d59ff0e | ||
| 
						 | 
					14da3a33cb | ||
| 
						 | 
					ea2035326d | ||
| 
						 | 
					2bfa708527 | ||
| 
						 | 
					72f911513e | ||
| 
						 | 
					3d0676a791 | ||
| 
						 | 
					4c4d227624 | ||
| 
						 | 
					0e8310fa6c | ||
| 
						 | 
					e3624562dc | ||
| 
						 | 
					d5057ec7b8 | ||
| 
						 | 
					72761b312b | ||
| 
						 | 
					a312523be4 | ||
| 
						 | 
					45fe47cea7 | ||
| 
						 | 
					ce356eec1f | ||
| 
						 | 
					cca1d180f5 | ||
| 
						 | 
					833ab4b083 | ||
| 
						 | 
					d358ca14a9 | ||
| 
						 | 
					3699ef06a4 | ||
| 
						 | 
					9dd80ca1f8 | ||
| 
						 | 
					621e8666ff | ||
| 
						 | 
					ec967d74f7 | ||
| 
						 | 
					3ccf02a300 | ||
| 
						 | 
					b6795ddfd2 | ||
| 
						 | 
					747fbce4ce | ||
| 
						 | 
					e1da8c9d2c | ||
| 
						 | 
					e78221d273 | ||
| 
						 | 
					6c303664f5 | ||
| 
						 | 
					544016d8e6 | ||
| 
						 | 
					263a1a3e8f | ||
| 
						 | 
					30bdf94102 | ||
| 
						 | 
					0dbaaadc06 | ||
| 
						 | 
					671c37b72b | ||
| 
						 | 
					2a9ba66922 | ||
| 
						 | 
					f8abd0ec0c | ||
| 
						 | 
					1a7048d69a | ||
| 
						 | 
					c70c08cd49 | ||
| 
						 | 
					a8f13286ff | ||
| 
						 | 
					b9e7569217 | ||
| 
						 | 
					057decfe3a | ||
| 
						 | 
					342a9a9418 | ||
| 
						 | 
					22f9cf2687 | ||
| 
						 | 
					26d6b2b5ce | ||
| 
						 | 
					169d50ed4a | ||
| 
						 | 
					82dfb505db | ||
| 
						 | 
					9c0d105d09 | ||
| 
						 | 
					ded02cfc29 | ||
| 
						 | 
					0cbed362cd | ||
| 
						 | 
					310e41cdf3 | ||
| 
						 | 
					a55bfdc436 | ||
| 
						 | 
					6ea8d7dac6 | ||
| 
						 | 
					9befdeb673 | ||
| 
						 | 
					5fb814b6b9 | ||
| 
						 | 
					9ac9cb963d | ||
| 
						 | 
					377d39122d | ||
| 
						 | 
					d1e94c7ac3 | ||
| 
						 | 
					6db3f7f1cb | ||
| 
						 | 
					58c0b0a6f7 | ||
| 
						 | 
					cca55247ed | ||
| 
						 | 
					d266c374ee | ||
| 
						 | 
					d358d71206 | ||
| 
						 | 
					5e6661eece | ||
| 
						 | 
					c1468ef7a5 | ||
| 
						 | 
					24763eaa73 | ||
| 
						 | 
					d8c2f31a87 | ||
| 
						 | 
					01b812ea76 | ||
| 
						 | 
					0807771b9e | ||
| 
						 | 
					103e50a561 | ||
| 
						 | 
					3a914e33e9 | ||
| 
						 | 
					2172f402a5 | ||
| 
						 | 
					8c138fe89c | ||
| 
						 | 
					7881f7da0b | ||
| 
						 | 
					d17a9de79e | ||
| 
						 | 
					8e74c63e15 | ||
| 
						 | 
					80dd576ad2 | ||
| 
						 | 
					cb922b646f | ||
| 
						 | 
					5d8b5b0935 | ||
| 
						 | 
					35bd2523e2 | ||
| 
						 | 
					f45a9b9760 | ||
| 
						 | 
					f48cd95bbc | ||
| 
						 | 
					7558c20973 | ||
| 
						 | 
					6ddc79b6ed | ||
| 
						 | 
					ff5921573a | ||
| 
						 | 
					d4ad77d326 | ||
| 
						 | 
					a6917fecb1 | ||
| 
						 | 
					58877f04e3 | ||
| 
						 | 
					d4707e2185 | ||
| 
						 | 
					f633302c73 | ||
| 
						 | 
					36413c011f | ||
| 
						 | 
					833281dcb9 | ||
| 
						 | 
					07bbd766c5 | ||
| 
						 | 
					c7c8e649f1 | ||
| 
						 | 
					c0e1b1aec5 | ||
| 
						 | 
					9735d21b9d | ||
| 
						 | 
					705565d745 | ||
| 
						 | 
					63088e0e61 | ||
| 
						 | 
					887c93e198 | ||
| 
						 | 
					2ca48823b1 | ||
| 
						 | 
					e7de137b29 | ||
| 
						 | 
					c1ad7fd92b | ||
| 
						 | 
					3779919551 | ||
| 
						 | 
					8e0d101997 | ||
| 
						 | 
					654b68d602 | ||
| 
						 | 
					70c03f5e44 | ||
| 
						 | 
					e56ec4a146 | ||
| 
						 | 
					5ffd127384 | ||
| 
						 | 
					051eb4d563 | ||
| 
						 | 
					e740665cab | ||
| 
						 | 
					abb9d47c90 | ||
| 
						 | 
					2dd2b33030 | ||
| 
						 | 
					69f15e4e95 | ||
| 
						 | 
					b0ea7976bf | ||
| 
						 | 
					9d939b6d5d | ||
| 
						 | 
					de805b6772 | ||
| 
						 | 
					cb25a0aa48 | ||
| 
						 | 
					72eff2cf6a | ||
| 
						 | 
					1c5fcb0791 | ||
| 
						 | 
					48fb176fbc | ||
| 
						 | 
					4d090d85f4 | ||
| 
						 | 
					81c5847434 | ||
| 
						 | 
					d48a811f6c | ||
| 
						 | 
					b7f52b414e | ||
| 
						 | 
					ea7aaf2eca | ||
| 
						 | 
					432ee9d150 | ||
| 
						 | 
					b4a59475d2 | ||
| 
						 | 
					2177919edb | ||
| 
						 | 
					87f114a1d0 | ||
| 
						 | 
					928a20b540 | ||
| 
						 | 
					b9022497d8 | ||
| 
						 | 
					582c2bf7b0 | ||
| 
						 | 
					663ba5c41f | ||
| 
						 | 
					daf5bcea99 | ||
| 
						 | 
					a29f155301 | ||
| 
						 | 
					941e317c97 | ||
| 
						 | 
					3fbf035923 | ||
| 
						 | 
					21bcf6abd8 | ||
| 
						 | 
					26e810d8a9 | ||
| 
						 | 
					4d1a52d463 | ||
| 
						 | 
					83df47cd7a | ||
| 
						 | 
					c5bbb78ffe | ||
| 
						 | 
					e0e5a772f4 | ||
| 
						 | 
					e39ae87ea3 | ||
| 
						 | 
					8b0a614e43 | ||
| 
						 | 
					c61664c2b2 | ||
| 
						 | 
					15e7e4f37d | ||
| 
						 | 
					ab8371c6d7 | ||
| 
						 | 
					8c777990a5 | ||
| 
						 | 
					ec5e85b84e | ||
| 
						 | 
					ab4e8663e1 | ||
| 
						 | 
					a4f783b51b | ||
| 
						 | 
					479cf76e55 | ||
| 
						 | 
					33639166a2 | ||
| 
						 | 
					709aad28ed | ||
| 
						 | 
					5892b2e4db | ||
| 
						 | 
					f1f73b8e1d | ||
| 
						 | 
					0fdc08c551 | ||
| 
						 | 
					5be57da075 | ||
| 
						 | 
					147184eb06 | ||
| 
						 | 
					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 | 
							
								
								
									
										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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ pkgconfig_DATA = \
 | 
				
			|||||||
BUILT_SOURCES = $(top_srcdir)/.version
 | 
					BUILT_SOURCES = $(top_srcdir)/.version
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
	     .version \
 | 
						     .version \
 | 
				
			||||||
	     contrib/osmo-mgw.spec.in \
 | 
						     README.md \
 | 
				
			||||||
	     debian \
 | 
						     debian \
 | 
				
			||||||
	     git-version-gen \
 | 
						     git-version-gen \
 | 
				
			||||||
	     osmoappdesc.py \
 | 
						     osmoappdesc.py \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								README
									
									
									
									
									
								
							@@ -1,24 +0,0 @@
 | 
				
			|||||||
About OsmoMGW
 | 
					 | 
				
			||||||
=============
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OsmoMGW originated from the OpenBSC project, which started as a minimalistic
 | 
					 | 
				
			||||||
all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
 | 
					 | 
				
			||||||
maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
 | 
					 | 
				
			||||||
IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
 | 
					 | 
				
			||||||
approach to fully independent separate programs as in typical GSM networks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OsmoMGW was one of the parts split off from the old openbsc.git. It originated
 | 
					 | 
				
			||||||
as a solution to merely navigate RTP streams through a NAT, but has since
 | 
					 | 
				
			||||||
matured to a Media Gateway implementation that is capable of streaming RTP for
 | 
					 | 
				
			||||||
2G (AoIP) and 3G (IuCS) GSM networks as well as (still not implemented at time
 | 
					 | 
				
			||||||
of writing) transcoding between TRAU, various RTP payloads and IuUP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The OsmoMGW program exposes an MGCP interface towards clients like OsmoMSC and
 | 
					 | 
				
			||||||
OsmoBSC, and receives and sends RTP streams as configured via MGCP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC (found
 | 
					 | 
				
			||||||
in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Find OsmoMGW issue tracker and wiki online at
 | 
					 | 
				
			||||||
https://osmocom.org/projects/osmo-mgw
 | 
					 | 
				
			||||||
https://osmocom.org/projects/osmo-mgw/wiki
 | 
					 | 
				
			||||||
							
								
								
									
										102
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					osmo-mgw - Osmocom MGW (Media GateWay) Implementation
 | 
				
			||||||
 | 
					=====================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This repository contains a C-language implementation of an MGW (Media
 | 
				
			||||||
 | 
					GateWay) for use [not only] within the 2G (GSM) and/or 3G (UMTS)
 | 
				
			||||||
 | 
					Cellular Network built using Osmocom CNI (Cellular Network
 | 
				
			||||||
 | 
					Infrastructure) software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The OsmoMGW program provides an MGCP interface towards an MGCP call agent
 | 
				
			||||||
 | 
					(client) like OsmoMSC and OsmoBSC, and receives and sends RTP streams as
 | 
				
			||||||
 | 
					configured via the MGCP control plane.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This Media Gateway implementation is capable of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* streaming RTP for 2G (3GPP AoIP and Abis-over-IP)
 | 
				
			||||||
 | 
					* streaming RTP for 3G (IuCS including the IuFP protocol)
 | 
				
			||||||
 | 
					* TDM (E1/T1) based Abis interface with TRAU frames on 16k sub-slots
 | 
				
			||||||
 | 
					* basic support for LCLS (Local Call, Local Switch) related features
 | 
				
			||||||
 | 
					* various built-in translation capabilities
 | 
				
			||||||
 | 
					  * between Abis TRAU frames and RTP formats
 | 
				
			||||||
 | 
					  * between 2G AMR/RTP and 3G AMR/IuFP/RTP
 | 
				
			||||||
 | 
					  * between bandwidth-efficient and octet-aligned AMR
 | 
				
			||||||
 | 
					  * between different standards for encapsulating GSM HR codec frames in RTP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw is typically co-located with
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * osmo-bsc (GSM BSC)
 | 
				
			||||||
 | 
					 * osmo-msc (GSM/UMTS MSC)
 | 
				
			||||||
 | 
					 * osmo-hnbgw (UMTS HNBGW); osmo-mgw implements RTP relay between Iuh
 | 
				
			||||||
 | 
					   and IuCS interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC
 | 
				
			||||||
 | 
					(found in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Homepage
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can find the OsmoMGW issue tracker and wiki online at
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/osmo-mgw> and <https://osmocom.org/projects/osmo-mgw/wiki>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GIT Repository
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can clone from the official osmo-mgw.git repository using
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Documentation
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					User Manuals and VTY reference manuals are [optionally] built in PDF form
 | 
				
			||||||
 | 
					as part of the build process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pre-rendered PDF version of the current "master" can be found at
 | 
				
			||||||
 | 
					[User Manual](https://ftp.osmocom.org/docs/latest/osmomgw-usermanual.pdf)
 | 
				
			||||||
 | 
					as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmomgw-vty-reference.pdf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Mailing List
 | 
				
			||||||
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Discussions related to osmo-mgw are happening on the
 | 
				
			||||||
 | 
					openbsc@lists.osmocom.org mailing list, please see
 | 
				
			||||||
 | 
					<https://lists.osmocom.org/mailman/listinfo/openbsc> for subscription
 | 
				
			||||||
 | 
					options and the list archive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please observe the [Osmocom Mailing List
 | 
				
			||||||
 | 
					Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
 | 
				
			||||||
 | 
					when posting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Contributing
 | 
				
			||||||
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Our coding standards are described at
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We use a gerrit based patch submission/review process for managing
 | 
				
			||||||
 | 
					contributions.  Please see
 | 
				
			||||||
 | 
					<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
 | 
				
			||||||
 | 
					more details
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The current patch queue for osmo-mgw can be seen at
 | 
				
			||||||
 | 
					<https://gerrit.osmocom.org/#/q/project:osmo-mgw+status:open>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					History
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoMGW originated from the OpenBSC project, which started as a minimalistic
 | 
				
			||||||
 | 
					all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
 | 
				
			||||||
 | 
					maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
 | 
				
			||||||
 | 
					IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
 | 
				
			||||||
 | 
					approach to fully independent separate programs as in typical GSM networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoMGW was one of the parts split off from the old openbsc.git. It originated
 | 
				
			||||||
 | 
					as a solution to merely navigate RTP streams through a NAT, but has since
 | 
				
			||||||
 | 
					matured.
 | 
				
			||||||
@@ -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:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								TODO-RELEASE
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								TODO-RELEASE
									
									
									
									
									
								
							@@ -1,27 +1,11 @@
 | 
				
			|||||||
# When cleaning up this file upon a release:
 | 
					# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
 | 
				
			||||||
#
 | 
					# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
 | 
				
			||||||
# - Note that the release version number is entirely unrelated to the API
 | 
					# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
 | 
				
			||||||
#   versions. A release version 5.2.3 may happily have an API version of 42:7:5.
 | 
					# LIBVERSION=c:r:a
 | 
				
			||||||
#
 | 
					# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
 | 
				
			||||||
# - Bump API version in src/lib*/Makefile.am files according to chapter
 | 
					# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
 | 
				
			||||||
#   "Library interface versions" of the libtool documentation.
 | 
					# If any interfaces have been added since the last public release: c:r:a + 1.
 | 
				
			||||||
#   https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
 | 
					# If any interfaces have been removed or changed since the last public release: c:r:0.
 | 
				
			||||||
#
 | 
					#library	what			description / commit summary line
 | 
				
			||||||
# - Iff the 'current' API version has changed, rename debian/lib*.install
 | 
					libosmocore		bump_dep; workaround	Bump libosmocore version dependency after I68328adb952ca8833ba047cb3b49ccc6f8a1f1b5
 | 
				
			||||||
#
 | 
											has been merged to libosmocore.git; then remove my_msgb_copy_c wrapper function.
 | 
				
			||||||
# API version bumping for the impatient:
 | 
					 | 
				
			||||||
# LIBVERSION=c:r:a  (current:revision_of_current:backwards_compat_age)
 | 
					 | 
				
			||||||
# 5:2:4 means that
 | 
					 | 
				
			||||||
# - this implements version 5 of the API;
 | 
					 | 
				
			||||||
# - this is the 2nd (compatible) revision of API version 5;
 | 
					 | 
				
			||||||
# - this is backwards compatible to all APIs since 4 versions ago,
 | 
					 | 
				
			||||||
#   i.e. callers that need API versions from 1 to 5 can use this.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Bumping API versions recipe:
 | 
					 | 
				
			||||||
# If the library source code has changed at all since the last update, r++;
 | 
					 | 
				
			||||||
# If any interfaces have been added, removed, or changed since the last update, c++, r=0;
 | 
					 | 
				
			||||||
# If any interfaces have been added since the last public release, a++;
 | 
					 | 
				
			||||||
# If any interfaces have been removed or changed since the last public release, a=0.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#library		what		description / commit summary line
 | 
					 | 
				
			||||||
update dependency to libosmocore > 1.5.1 for our use of osmo_sock_set_dscp()
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								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,17 @@ 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.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
				
			||||||
 | 
					CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread"
 | 
				
			||||||
 | 
					LDFLAGS="$LDFLAGS -pthread"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -81,21 +80,13 @@ AC_ARG_ENABLE(werror,
 | 
				
			|||||||
if test x"$werror" = x"yes"
 | 
					if test x"$werror" = x"yes"
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	WERROR_FLAGS="-Werror"
 | 
						WERROR_FLAGS="-Werror"
 | 
				
			||||||
 | 
						WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
						WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
						WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
				
			||||||
	CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
						CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
				
			||||||
	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 +114,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])
 | 
				
			||||||
@@ -213,5 +204,4 @@ AC_OUTPUT(
 | 
				
			|||||||
    doc/manuals/Makefile
 | 
					    doc/manuals/Makefile
 | 
				
			||||||
    contrib/Makefile
 | 
					    contrib/Makefile
 | 
				
			||||||
    contrib/systemd/Makefile
 | 
					    contrib/systemd/Makefile
 | 
				
			||||||
    contrib/osmo-mgw.spec
 | 
					 | 
				
			||||||
    Makefile)
 | 
					    Makefile)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ export deps inst
 | 
				
			|||||||
osmo-clean-workspace.sh
 | 
					osmo-clean-workspace.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir "$deps" || true
 | 
					mkdir "$deps" || true
 | 
				
			||||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
 | 
					osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
					verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
				
			|||||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
					export LD_LIBRARY_PATH="$inst/lib"
 | 
				
			||||||
export PATH="$inst/bin:$PATH"
 | 
					export PATH="$inst/bin:$PATH"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-build-dep.sh libosmo-netif "" --disable-doxygen
 | 
				
			||||||
osmo-build-dep.sh libosmo-abis
 | 
					osmo-build-dep.sh libosmo-abis
 | 
				
			||||||
osmo-build-dep.sh libosmo-netif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Additional configure options and depends
 | 
					# Additional configure options and depends
 | 
				
			||||||
CONFIG=""
 | 
					CONFIG=""
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,137 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# spec file for package osmo-mgw
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# All modifications and additions to the file contributed by third parties
 | 
					 | 
				
			||||||
# remain the property of their copyright owners, unless otherwise agreed
 | 
					 | 
				
			||||||
# upon. The license for this file, and modifications and additions to the
 | 
					 | 
				
			||||||
# file, is the same license as for the pristine package itself (unless the
 | 
					 | 
				
			||||||
# license for the pristine package is not an Open Source License, in which
 | 
					 | 
				
			||||||
# case the license is the MIT License). An "Open Source License" is a
 | 
					 | 
				
			||||||
# license that conforms to the Open Source Definition (Version 1.9)
 | 
					 | 
				
			||||||
# published by the Open Source Initiative.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Please submit bugfixes or comments via http://bugs.opensuse.org/
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Name:           osmo-mgw
 | 
					 | 
				
			||||||
Version:        @VERSION@
 | 
					 | 
				
			||||||
Release:        0
 | 
					 | 
				
			||||||
Summary:        Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					 | 
				
			||||||
License:        AGPL-3.0-or-later AND GPL-2.0-or-later
 | 
					 | 
				
			||||||
Group:          Hardware/Mobile
 | 
					 | 
				
			||||||
URL:            https://osmocom.org/projects/osmo-mgw
 | 
					 | 
				
			||||||
Source:         %{name}-%{version}.tar.xz
 | 
					 | 
				
			||||||
BuildRequires:  automake >= 1.9
 | 
					 | 
				
			||||||
BuildRequires:  libtool >= 2
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig >= 0.20
 | 
					 | 
				
			||||||
%if 0%{?suse_version}
 | 
					 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					 | 
				
			||||||
%endif
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.1.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.5.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.1.0
 | 
					 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.1.0
 | 
					 | 
				
			||||||
%{?systemd_requires}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description
 | 
					 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-client8
 | 
					 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					 | 
				
			||||||
Group:          System/Libraries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-client8
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					 | 
				
			||||||
Requires:       libosmo-mgcp-client8 = %{version}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This subpackage contains libraries and header files for developing
 | 
					 | 
				
			||||||
applications that want to make use of libosmo-mgcp-client.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%package -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway server library
 | 
					 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%description -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
Osmocom's Media Gateway Control Protocol server library.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This subpackage contains libraries and header files for developing
 | 
					 | 
				
			||||||
applications that want to make use of libosmo-mgcp.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%prep
 | 
					 | 
				
			||||||
%setup -q
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%build
 | 
					 | 
				
			||||||
echo "%{version}" >.tarball-version
 | 
					 | 
				
			||||||
autoreconf -fi
 | 
					 | 
				
			||||||
%configure \
 | 
					 | 
				
			||||||
  --disable-static \
 | 
					 | 
				
			||||||
  --docdir=%{_docdir}/%{name} \
 | 
					 | 
				
			||||||
  --with-systemdsystemunitdir=%{_unitdir}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make %{?_smp_mflags}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%install
 | 
					 | 
				
			||||||
%make_install
 | 
					 | 
				
			||||||
find %{buildroot} -type f -name "*.la" -delete -print
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%check
 | 
					 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%post   -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
					 | 
				
			||||||
%postun -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%if 0%{?suse_version}
 | 
					 | 
				
			||||||
%preun
 | 
					 | 
				
			||||||
%service_del_preun osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%postun
 | 
					 | 
				
			||||||
%service_del_postun osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%pre
 | 
					 | 
				
			||||||
%service_add_pre osmo-mgw.service
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%post
 | 
					 | 
				
			||||||
%service_add_post osmo-mgw.service
 | 
					 | 
				
			||||||
%endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files
 | 
					 | 
				
			||||||
%license COPYING
 | 
					 | 
				
			||||||
%doc AUTHORS README
 | 
					 | 
				
			||||||
%dir %{_docdir}/%{name}/examples
 | 
					 | 
				
			||||||
%dir %{_docdir}/%{name}/examples/osmo-mgw
 | 
					 | 
				
			||||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
 | 
					 | 
				
			||||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
 | 
					 | 
				
			||||||
%{_bindir}/osmo-mgw
 | 
					 | 
				
			||||||
%{_unitdir}/osmo-mgw.service
 | 
					 | 
				
			||||||
%dir %{_sysconfdir}/osmocom
 | 
					 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-client8
 | 
					 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.8*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					 | 
				
			||||||
%{_libdir}/pkgconfig/libosmo-mgcp-client.pc
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom/mgcp_client
 | 
					 | 
				
			||||||
%{_includedir}/osmocom/mgcp_client/*.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%files -n libosmo-mgcp-devel
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom
 | 
					 | 
				
			||||||
%dir %{_includedir}/osmocom/mgcp
 | 
					 | 
				
			||||||
%{_includedir}/osmocom/mgcp/*.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%changelog
 | 
					 | 
				
			||||||
@@ -1,11 +1,24 @@
 | 
				
			|||||||
[Unit]
 | 
					[Unit]
 | 
				
			||||||
Description=Osmocom Media Gateway (MGW)
 | 
					Description=Osmocom Media Gateway (MGW)
 | 
				
			||||||
 | 
					After=network-online.target
 | 
				
			||||||
 | 
					Wants=network-online.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Service]
 | 
					[Service]
 | 
				
			||||||
Type=simple
 | 
					Type=simple
 | 
				
			||||||
 | 
					LimitNOFILE=65536
 | 
				
			||||||
 | 
					StateDirectory=osmocom
 | 
				
			||||||
 | 
					WorkingDirectory=%S/osmocom
 | 
				
			||||||
Restart=always
 | 
					Restart=always
 | 
				
			||||||
 | 
					User=osmocom
 | 
				
			||||||
 | 
					Group=osmocom
 | 
				
			||||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
					ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
RestartSec=2
 | 
					RestartSec=2
 | 
				
			||||||
 | 
					AmbientCapabilities=CAP_SYS_NICE
 | 
				
			||||||
 | 
					# CPU scheduling policy:
 | 
				
			||||||
 | 
					CPUSchedulingPolicy=rr
 | 
				
			||||||
 | 
					# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
 | 
				
			||||||
 | 
					CPUSchedulingPriority=1
 | 
				
			||||||
 | 
					# See sched(7) for further details on real-time policies and priorities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Install]
 | 
					[Install]
 | 
				
			||||||
WantedBy=multi-user.target
 | 
					WantedBy=multi-user.target
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										513
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										513
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,516 @@
 | 
				
			|||||||
 | 
					osmo-mgw (1.14.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * jenkins.sh: libosmo-netif no longer depends on libosmo-abis
 | 
				
			||||||
 | 
					  * jenkins.sh: Use --disable-doxygen configure param
 | 
				
			||||||
 | 
					  * mgcp-client: Fix wrong value passed to strerror()
 | 
				
			||||||
 | 
					  * mgcp_client_internal.h: Add missing header dependency
 | 
				
			||||||
 | 
					  * mgcp-cli: Mark iofd ptr as NULL when freed
 | 
				
			||||||
 | 
					  * mgcp-cli: Improve error handling around mgcp_msg_gen() return
 | 
				
			||||||
 | 
					  * mgcp-cli: Fix filling in wrong local IP address of SDP Origin o=
 | 
				
			||||||
 | 
					  * mgw: Drop own MGCP extension 'noanswer'
 | 
				
			||||||
 | 
					  * cosmetic: mgw: Fix indentation whitespace
 | 
				
			||||||
 | 
					  * mgcp-client: Fix regression checking null ptr
 | 
				
			||||||
 | 
					  * mgw: Rename and move code freeing endp connection
 | 
				
			||||||
 | 
					  * mgw: Rename and move several get_conn funcs acting on endp object
 | 
				
			||||||
 | 
					  * mgw: mgcp_network.c: Simplify use of conn_rtp ptr
 | 
				
			||||||
 | 
					  * mgw: Clean up access to conn_rtp from conn
 | 
				
			||||||
 | 
					  * mgw: Avoid 2nd lookup of conn in endp during CRCX
 | 
				
			||||||
 | 
					  * cosmetic: mgw: iuup: Update comment
 | 
				
			||||||
 | 
					  * mgw: constify mgcp_endp_avail() param
 | 
				
			||||||
 | 
					  * mgcp_endp: Add helpers accessing endp connections
 | 
				
			||||||
 | 
					  * mgw: mgcp_protocol: assert freeing last conn allows creating new conn
 | 
				
			||||||
 | 
					  * mgw: Split conn mode parsing and applying into conn
 | 
				
			||||||
 | 
					  * mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables
 | 
				
			||||||
 | 
					  * mgw: Use bool instead of int in local var
 | 
				
			||||||
 | 
					  * Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port()
 | 
				
			||||||
 | 
					  * mgw: Split mgcp_rtp_end to its own file
 | 
				
			||||||
 | 
					  * mgw: Introduce mgcp_rtp_end_init()
 | 
				
			||||||
 | 
					  * mgw: Introduce struct mgcp_codecset struct
 | 
				
			||||||
 | 
					  * mgw: Cleanup rtp_endp fields in its own function
 | 
				
			||||||
 | 
					  * mgw: Move force_ptime logic outside of main CRCX func handler
 | 
				
			||||||
 | 
					  * mgw: Move several params setting to mgcp_rtp_end_init()
 | 
				
			||||||
 | 
					  * mgw: Simplify and redo code around ssrc patch feature
 | 
				
			||||||
 | 
					  * mgw: Clean up code allocating conn_rtp rtp/rtcp sockets
 | 
				
			||||||
 | 
					  * mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk
 | 
				
			||||||
 | 
					  * mgw: CRCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: MDCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: DLCX: Split mgcp header pars parsing into a previous step
 | 
				
			||||||
 | 
					  * mgw: Decouple SDP parsing step from conn obj update
 | 
				
			||||||
 | 
					  * mgw: Remove wrong TODO comment
 | 
				
			||||||
 | 
					  * mgw: MDCX: Simplify early return code paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Mychaela N. Falconia ]
 | 
				
			||||||
 | 
					  * E1 cosmetic: reduce white space in hard-coded TRAU-DL frames
 | 
				
			||||||
 | 
					  * E1: replace idle_tf_efr[] with a better version
 | 
				
			||||||
 | 
					  * E1: replace idle_tf_fr[] with a better version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Wed, 12 Feb 2025 12:30:33 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.13.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_network: use an uint16_t to store the port number
 | 
				
			||||||
 | 
					  * mgcp_network: add missing ntohs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * tests/mgcp/mgcp_test: Add some extra asserts in code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Thu, 12 Sep 2024 13:53:19 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.13.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * add mgcp_conn_rtp_type_names[]
 | 
				
			||||||
 | 
					  * mgcp_parse_audio_port_pt(): fix buffer overflow
 | 
				
			||||||
 | 
					  * client: replace two assertions with graceful error handling
 | 
				
			||||||
 | 
					  * systemd,manual: set LimitNOFILE=65536
 | 
				
			||||||
 | 
					  * IuUP: allow Initialization from any address if not yet set
 | 
				
			||||||
 | 
					  * check_rtp_origin: drop special case for legacy IuUP hack
 | 
				
			||||||
 | 
					  * mgcp_client_test: fix function name
 | 
				
			||||||
 | 
					  * fix possible NULL deref on early media
 | 
				
			||||||
 | 
					  * client: move some items to internal header
 | 
				
			||||||
 | 
					  * client: safely handle dealloc on event dispatch
 | 
				
			||||||
 | 
					  * build: move mgcp/*.h to noinst_HEADERS, drop RPM libosmo-mgcp-devel
 | 
				
			||||||
 | 
					  * client: deprecate legacy API
 | 
				
			||||||
 | 
					  * client: collapse codecs[] and ptmap[]; allow codec variants
 | 
				
			||||||
 | 
					  * client: allow MGCP_MAX_CODECS entries
 | 
				
			||||||
 | 
					  * client SDP: more verbose error logging
 | 
				
			||||||
 | 
					  * mgcp_client_test: add test_parse_response()
 | 
				
			||||||
 | 
					  * drop (now) unused code
 | 
				
			||||||
 | 
					  * tests/mgcp: add update_exp target
 | 
				
			||||||
 | 
					  * drop get_net_downlink_format_cb
 | 
				
			||||||
 | 
					  * drop cfg 'sdp audio fmtp-extra'
 | 
				
			||||||
 | 
					  * mgcp_codec_decide: remove redundant lookup
 | 
				
			||||||
 | 
					  * tweak DEBUG log
 | 
				
			||||||
 | 
					  * mgcp_test: fix false negatives in test output
 | 
				
			||||||
 | 
					  * mgw: do not fail MGCP on codec mismatch
 | 
				
			||||||
 | 
					  * mgcp-client: always send 'm=audio' line
 | 
				
			||||||
 | 
					  * mgcp_test.c: verify osmo-mgw accepts m=audio 0
 | 
				
			||||||
 | 
					  * mgcp_test.c: fix various missing '\r' and '\n'
 | 
				
			||||||
 | 
					  * mgcp_test: test a=ptime:20, not 40
 | 
				
			||||||
 | 
					  * mgcp_test: add CRCX for IUFP in sendrecv
 | 
				
			||||||
 | 
					  * do not FAIL on CRCX in sendrecv mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Keith Whyte ]
 | 
				
			||||||
 | 
					  * vty and log: also show local port for RTP conns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Andreas Eversberg ]
 | 
				
			||||||
 | 
					  * Use uniform log format for default config files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp_network: Improve err logging when rtp pkt from unexpected origin comes in
 | 
				
			||||||
 | 
					  * cosmetic: Fix line indentation
 | 
				
			||||||
 | 
					  * IuUP: Allow Initialization with set rem IP address and unset rem port
 | 
				
			||||||
 | 
					  * mgcp-client: Transmit remote IP addr in CRCX if known and port=0
 | 
				
			||||||
 | 
					  * Fix IuUP RTP hdr seqnr field not incremented
 | 
				
			||||||
 | 
					  * iuup: Increment RTP hdr seqnr even if Tx over UDP fails
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * mgcp: simplify getting msgb tail in mgcp_msg_terminate_nul()
 | 
				
			||||||
 | 
					  * mgcp: reserve once byte for '\0' in mgcp_do_read()
 | 
				
			||||||
 | 
					  * mgcp: correctly put NUL character in mgcp_msg_terminate_nul()
 | 
				
			||||||
 | 
					  * build: include README into the release tarball
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ neels ]
 | 
				
			||||||
 | 
					  * Revert "drop (now) unused code"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Convert README to README.md and expand like in other projects
 | 
				
			||||||
 | 
					  * migrate mgcp_client from osmo_wqueue to osmo_io
 | 
				
			||||||
 | 
					  * mgw: Add our usual SIGABRT, SIGUSR1 signal handlers
 | 
				
			||||||
 | 
					  * don't log useless "transcoding disabled" message
 | 
				
			||||||
 | 
					  * remove strange loop for non-existant transcoding support
 | 
				
			||||||
 | 
					  * simplify unused transcoding/processing call-back
 | 
				
			||||||
 | 
					  * remove osmo_fd from mgcp_create_bind()
 | 
				
			||||||
 | 
					  * Change msgb ownership in processing of received msgb
 | 
				
			||||||
 | 
					  * cosmetic: make linter happy
 | 
				
			||||||
 | 
					  * Convert RTP/RTCP/OSMUX I/O from osmo_fd to osmo_io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * contrib: remove rpm spec file
 | 
				
			||||||
 | 
					  * contrib/systemd: run as osmocom user
 | 
				
			||||||
 | 
					  * doc: example configs: fix deprecation warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Mychaela N. Falconia ]
 | 
				
			||||||
 | 
					  * E1: support HRv1 codec on both 16k and 8k subslots
 | 
				
			||||||
 | 
					  * fix E1 TS output when used with osmo-e1d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Wed, 24 Jul 2024 15:44:47 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.12.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp-client: Fix missing include in mgcp_client_pool.h
 | 
				
			||||||
 | 
					  * mgcp-client: Introduce API osmo_mgcpc_ep_local_name()
 | 
				
			||||||
 | 
					  * mgw: Configure IuUP if codec set during MDCX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Thu, 28 Sep 2023 15:58:17 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.12.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_sdp: add spec reference
 | 
				
			||||||
 | 
					  * mgcp_sdp: cosmetic: remove newline
 | 
				
			||||||
 | 
					  * mgcp_endp: cosmetic move mgcp_endp_release to the end
 | 
				
			||||||
 | 
					  * mgcp_endp: cosmetic: remove unnecessary new line
 | 
				
			||||||
 | 
					  * mgcp_e1: fix log output
 | 
				
			||||||
 | 
					  * mgcp_e1: be more frugal withe E1 line resources
 | 
				
			||||||
 | 
					  * mgcp_client: fix sourcecode formatting
 | 
				
			||||||
 | 
					  * mgcp_e1: fix typo
 | 
				
			||||||
 | 
					  * mgcp_e1: rewrite comment
 | 
				
			||||||
 | 
					  * mgcp_e1: rename e1_send to e1_send_ts_frame
 | 
				
			||||||
 | 
					  * mgcp_e1: cosmetic: rewrite comment
 | 
				
			||||||
 | 
					  * Revert "mgcp_codec: do not differentiate between oa and bwe when comparing codec"
 | 
				
			||||||
 | 
					  * mgcp_codec: fix oa/bwe comparison in mgcp_codec_pt_translate()
 | 
				
			||||||
 | 
					  * mgcp_codec: refactor payload type converstion
 | 
				
			||||||
 | 
					  * mgcp_codec: cosmetic: remove line break in api-doc
 | 
				
			||||||
 | 
					  * mgcp_network: fix apidoc
 | 
				
			||||||
 | 
					  * mgcp_vty: add warnings for deprecated config options
 | 
				
			||||||
 | 
					  * mgcp_codec: move mgcp_codec_decide down
 | 
				
			||||||
 | 
					  * mgcp_codec: fix codec decision
 | 
				
			||||||
 | 
					  * mgcp_network: do not deliver RTP packets with unpatched PT
 | 
				
			||||||
 | 
					  * mgcp_codec: be sensitive about IuFP when checking codecs
 | 
				
			||||||
 | 
					  * mgcp_client.h: also add spec ref to the other 3gpp defined payload types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * cosmetic: Fix grammar suggesting reading _the_ user manual
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ arehbein ]
 | 
				
			||||||
 | 
					  * Transition to use of 'telnet_init_default'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * mgcp_client: mgcp_msg_gen: add more error logs
 | 
				
			||||||
 | 
					  * mgcp_client_pool: add mgcp_client_pool_empty()
 | 
				
			||||||
 | 
					  * Cosmetic: mgcp_client: fix typo
 | 
				
			||||||
 | 
					  * debian: set compat level to 10
 | 
				
			||||||
 | 
					  * systemd: depend on networking-online.target
 | 
				
			||||||
 | 
					  * Cosmetic: fix a typo
 | 
				
			||||||
 | 
					  * mgcp_client: check rc of map_str_to_codec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp_network: Unregister osmo_fd before closing fd
 | 
				
			||||||
 | 
					  * mgcp-client: Call osmo_fd_unregister() before closing and changing bfd->fd
 | 
				
			||||||
 | 
					  * mgcp-client: Drop unused struct mgcp_client field
 | 
				
			||||||
 | 
					  * mgcp_client: Introduce mgcp_client_conf_alloc(), deprecate mgcp_client_conf_init()
 | 
				
			||||||
 | 
					  * mgcp-client: Move some static functions further above
 | 
				
			||||||
 | 
					  * mgw: Allow auditing speciall 'null' endpoint
 | 
				
			||||||
 | 
					  * mgcp-client: Add keepalive feature
 | 
				
			||||||
 | 
					  * mgcp_client: pool: Only pick clients with an MGCP link considered to be UP
 | 
				
			||||||
 | 
					  * mgcp-client: Always mark client as UP if keepalive request-interval disabled
 | 
				
			||||||
 | 
					  * mgcp-client: Mark client as UP when keepalive request-interval/timeout is disabled through VTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * */Makefile.am: libraries shall not be in AM_LDFLAGS
 | 
				
			||||||
 | 
					  * tests: use -no-install libtool flag to avoid ./lt-* scripts
 | 
				
			||||||
 | 
					  * tests: $(BUILT_SOURCES) is not defined, depend on osmo-mgw
 | 
				
			||||||
 | 
					  * copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * mgcp_find_section_end(): skip spaces at start of SDP
 | 
				
			||||||
 | 
					  * mgcp_client: simpler error handling
 | 
				
			||||||
 | 
					  * mgcp: fix "L: a:" header parsing: heed ";" separator
 | 
				
			||||||
 | 
					  * mgcp_client: tweak extract_codec_name() implementation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Andreas Eversberg ]
 | 
				
			||||||
 | 
					  * ASCI: Add new mode for voice group/broadcast call
 | 
				
			||||||
 | 
					  * ASCI: Support conference briding with 1..n connections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 12 Sep 2023 14:48:51 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.11.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp-client: Remove impossible code path
 | 
				
			||||||
 | 
					  * mgcp_osmux: Drop duplicated conn_osmux_release_cid() in code path
 | 
				
			||||||
 | 
					  * Use Osmux default port define from libosmo-netif
 | 
				
			||||||
 | 
					  * osmux: Use new osmux APIs to let libosmo-netif alloc struct osmux_out_handle
 | 
				
			||||||
 | 
					  * mgw: Fix osmux conn local IP selection
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Fix wrong indentation
 | 
				
			||||||
 | 
					  * mgw: Use X-Osmux string define
 | 
				
			||||||
 | 
					  * Add Osmux log category
 | 
				
			||||||
 | 
					  * cosmetic: main: Properly format log_info_cat
 | 
				
			||||||
 | 
					  * osmux: Use better name for function which may allocate a new struct
 | 
				
			||||||
 | 
					  * osmux: Use osmo_sockaddr wherever possible
 | 
				
			||||||
 | 
					  * osmux: Log refcounting of osmux_handle_list
 | 
				
			||||||
 | 
					  * osmux: Fix memleak on error code path
 | 
				
			||||||
 | 
					  * osmux: don't store conn ptr inside shared osmux_handle
 | 
				
			||||||
 | 
					  * osmux: set log level of expected code path to INFO
 | 
				
			||||||
 | 
					  * cosmetic: vty: Fix indentation whitespace
 | 
				
			||||||
 | 
					  * osmux: Log sendto() error
 | 
				
			||||||
 | 
					  * cosmetic: mgcp_conn.h: fix indentation whitespace
 | 
				
			||||||
 | 
					  * osmux: Attach osmux to virtual trunk
 | 
				
			||||||
 | 
					  * osmux: Clean up helper macro osmux_chunk_length()
 | 
				
			||||||
 | 
					  * osmux: Get rid of static NULL talloc context
 | 
				
			||||||
 | 
					  * Fix typo in ratectr description
 | 
				
			||||||
 | 
					  * mgcp_conn: rename field s/rate_ctr_group/ctrg/g
 | 
				
			||||||
 | 
					  * Use 'static const' instead of 'const static' everywhere
 | 
				
			||||||
 | 
					  * osmux: Add connection and global rate counters
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Fix formatting of if-else brackets
 | 
				
			||||||
 | 
					  * osmux: Rename field osmux usage policy and define it with proper type
 | 
				
			||||||
 | 
					  * Use bool type instead of int in config field
 | 
				
			||||||
 | 
					  * osmux: Support local CID != remote CID
 | 
				
			||||||
 | 
					  * osmux: Fix incorrect rate_ctr_group used in mgcp_osmux.c
 | 
				
			||||||
 | 
					  * osmux: Improve per-conn tx rate counters
 | 
				
			||||||
 | 
					  * vty: show per-connection Osmux VTY stats
 | 
				
			||||||
 | 
					  * osmux: Rename field s/init/initialized
 | 
				
			||||||
 | 
					  * osmux: Allocate rate counters during initialization of osmux conn
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Drop extra empty line
 | 
				
			||||||
 | 
					  * osmux: Drop unneeded comment block
 | 
				
			||||||
 | 
					  * osmux: Lower log level when osmux batch received for unknown CID
 | 
				
			||||||
 | 
					  * osmux: Keep decoding osmux pkt if a batch contains an unknown CID
 | 
				
			||||||
 | 
					  * Allocate struct osmux_in_handle through new libosmo-netif APIs
 | 
				
			||||||
 | 
					  * osmux: Drop logging of osmux internal counters
 | 
				
			||||||
 | 
					  * osmux: cleanup misleading code calling rtp_bridge_cb
 | 
				
			||||||
 | 
					  * osmux: Unify rtp_conn osmux type into a single type
 | 
				
			||||||
 | 
					  * osmux: Match remote address in osmux_conn_lookup()
 | 
				
			||||||
 | 
					  * osmux: Fill in from_addr in struct osmo_rtp_msg_ctx
 | 
				
			||||||
 | 
					  * osmux: Log remote address upon rx of osmux pkt
 | 
				
			||||||
 | 
					  * send_dummy: Use proper condition to test if conn is osmux
 | 
				
			||||||
 | 
					  * Fix regression in detection of legacy dummy packets
 | 
				
			||||||
 | 
					  * Use new libosmocore API osmo_sockaddr_is_any()
 | 
				
			||||||
 | 
					  * Get rid of separate rtp_port field
 | 
				
			||||||
 | 
					  * osmux: Use available API to check if remote end is known
 | 
				
			||||||
 | 
					  * Add Osmux IPv6 support
 | 
				
			||||||
 | 
					  * Clean up local var pointers in mgcp_get_local_addr()
 | 
				
			||||||
 | 
					  * osmux: Change couple log lines to OSMUX category
 | 
				
			||||||
 | 
					  * osmux: Add square brackets around IPv6 address to distinguish port in log line
 | 
				
			||||||
 | 
					  * osmux: Drop unused role parameter
 | 
				
			||||||
 | 
					  * osmux: cosmetic: Fix indentation
 | 
				
			||||||
 | 
					  * Check once if remote addr is available when sending dummy packet
 | 
				
			||||||
 | 
					  * osmux: Simplify and constify param passing
 | 
				
			||||||
 | 
					  * osmux: Set conn->type during osmux_init_conn()
 | 
				
			||||||
 | 
					  * osmux: Make conn_osmux_{allocate,release}_local_cid() APIs static
 | 
				
			||||||
 | 
					  * osmux: Define osmux_dummy cfg as boolean
 | 
				
			||||||
 | 
					  * osmux: Move setting OSMUX_STATE_DISABLED to initializer function
 | 
				
			||||||
 | 
					  * osmux: Erase references to bsc-nat
 | 
				
			||||||
 | 
					  * mgcp_conn_dump(): Separate dump for osmux and iuup connections
 | 
				
			||||||
 | 
					  * osmux: Introduce osmux peer-behind-nat (on|off) and rework conn activation
 | 
				
			||||||
 | 
					  * osmux: Clean up mgcp_config osmux fields
 | 
				
			||||||
 | 
					  * cosmetic: Fix typo in comment
 | 
				
			||||||
 | 
					  * mgcp-client: pool: Improve documentation of some internal fields
 | 
				
			||||||
 | 
					  * mgcp-client: Avoid double iteration picking client from pool
 | 
				
			||||||
 | 
					  * mgcp-client: Fix typo in internal function name
 | 
				
			||||||
 | 
					  * mgcp-client: Rename internal field in mgcp_client_pool
 | 
				
			||||||
 | 
					  * mgcp-client: Move & rename helper function outside of vty code
 | 
				
			||||||
 | 
					  * mgcp-client: Create alloc() and free() internal APIs for mgcp_client_pool_member
 | 
				
			||||||
 | 
					  * mgcp-client: Move internal API acting on mgcp_client_pool to the correct file section
 | 
				
			||||||
 | 
					  * mgcp-client: Refactor reinit of mgcp clients
 | 
				
			||||||
 | 
					  * mgcp-client: Rearrange order of structs and APIs in header
 | 
				
			||||||
 | 
					  * mgcp-client: Rearrange internal backpointers
 | 
				
			||||||
 | 
					  * mgcp-client: Introduce APIs to manually select mgcp_client from pool
 | 
				
			||||||
 | 
					  * mgcp-client: vty: Write deprecation warning using non-mgw nodes
 | 
				
			||||||
 | 
					  * mgcp-client: Use random free local port by default
 | 
				
			||||||
 | 
					  * mgcp-client: Convert users supporting new MGW Pool VTY node during write-config
 | 
				
			||||||
 | 
					  * mgcp-client: Introduce API mgcp_client_pool_config_write
 | 
				
			||||||
 | 
					  * mgcp-client: Add new VTY commands under mgw node without mgw prefix
 | 
				
			||||||
 | 
					  * mgcp-client: Fix 'mgw endpoint-range' command dropped from old VTY node
 | 
				
			||||||
 | 
					  * mgcp-client: Refactor system keeping old users not calling mgcp_client_pool_config_write() working
 | 
				
			||||||
 | 
					  * mgcp-client: Fix no 'mgw ' prefix written in old VTY node
 | 
				
			||||||
 | 
					  * Fix misleading error log
 | 
				
			||||||
 | 
					  * mgcp_send: Use mgcp_conn_rtp_is_iuup() helper
 | 
				
			||||||
 | 
					  * cosmetic: Clarify and fix typos in comment
 | 
				
			||||||
 | 
					  * mgw: Log unexpected RTP AMR OA-vs-BE payload
 | 
				
			||||||
 | 
					  * Rename and move func checking if amr mode is explicitly configured
 | 
				
			||||||
 | 
					  * mgw: rx_rtp(): reorder checks and handlings
 | 
				
			||||||
 | 
					  * mgw: Rename s/mgcp_send_rtp/mgcp_conn_rtp_dispatch_rtp/
 | 
				
			||||||
 | 
					  * osmux: Rename function and pass msgb directly to it
 | 
				
			||||||
 | 
					  * osmux: Make sure RTP AMR feed to osmux is in octet-aligned mode
 | 
				
			||||||
 | 
					  * Improve logging on AMR OA<->BWE conversion failure
 | 
				
			||||||
 | 
					  * osmux: Rotate over available Osmux CID when allocating a new one
 | 
				
			||||||
 | 
					  * osmux: Use new osmux_xfrm_input API to set name on each link
 | 
				
			||||||
 | 
					  * iuup: Use osmo_amr_ft_valid() API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * libosmo-mgcp-client: add -no-undefined to *_la_LDFLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_e1: fix apidoc
 | 
				
			||||||
 | 
					  * mgcp_network: improve coment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Max ]
 | 
				
			||||||
 | 
					  * Set working directory in systemd service file
 | 
				
			||||||
 | 
					  * Add realtime scheduling and set priority in service file
 | 
				
			||||||
 | 
					  * ctrl: take both address and port from vty config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Make osmo_mgcpc_ep_fsm_pre_term() static
 | 
				
			||||||
 | 
					  * Support building with -Werror=strict-prototypes / -Werror=old-style-definition
 | 
				
			||||||
 | 
					  * Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
 | 
				
			||||||
 | 
					  * update outdated vty copyright statement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * mgcp_client_pool.h: add missing stdbool include
 | 
				
			||||||
 | 
					  * Fix various typos
 | 
				
			||||||
 | 
					  * mgcp_client: add new clearmode codec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * AMR->IuUP: do not crash on AMR data before IuUP Init
 | 
				
			||||||
 | 
					  * AMR->IuUP: properly translate Q -> FQC
 | 
				
			||||||
 | 
					  * IuUP->AMR: do not patch payload type a second time
 | 
				
			||||||
 | 
					  * IuUP->AMR: log whether converting to AMR OA or BE
 | 
				
			||||||
 | 
					  * AMR->IuUP: log conversion, like for the flipside
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 07 Feb 2023 16:58:41 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					osmo-mgw (1.8.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * attempt to fix RPM spec file after recent soversion bump
 | 
					  * attempt to fix RPM spec file after recent soversion bump
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@@ -1 +1 @@
 | 
				
			|||||||
9
 | 
					10
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -2,17 +2,16 @@ Source: osmo-mgw
 | 
				
			|||||||
Section: net
 | 
					Section: net
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
					Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
				
			||||||
Build-Depends: debhelper (>=9),
 | 
					Build-Depends: debhelper (>= 10),
 | 
				
			||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.5.0),
 | 
					               libosmocore-dev (>= 1.11.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.1.0),
 | 
					               libosmo-netif-dev (>= 1.6.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.1.0),
 | 
					               libosmo-abis-dev (>= 2.0.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.1.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 +20,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-client14
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
@@ -33,14 +32,6 @@ 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-client14 (= ${binary:Version}), ${misc:Depends}
 | 
				
			||||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
					Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw-doc
 | 
					 | 
				
			||||||
Architecture: all
 | 
					 | 
				
			||||||
Section: doc
 | 
					 | 
				
			||||||
Priority: optional
 | 
					 | 
				
			||||||
Depends: ${misc:Depends}
 | 
					 | 
				
			||||||
Description: ${misc:Package} PDF documentation
 | 
					 | 
				
			||||||
 Various manuals: user manual, VTY reference manual and/or
 | 
					 | 
				
			||||||
 protocol/interface manuals.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -1,12 +1,12 @@
 | 
				
			|||||||
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
 | 
				
			||||||
           2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
 | 
					           2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
           2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
 | 
					           2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
 | 
				
			||||||
           2016-2017 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
					           2016-2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
License:   AGPL-3.0+
 | 
					License:   AGPL-3.0+
 | 
				
			||||||
 This program is free software; you can redistribute it and/or modify
 | 
					 This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 it under the terms of the GNU Affero General Public License as published by
 | 
					 it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
@@ -22,7 +22,7 @@ License:   AGPL-3.0+
 | 
				
			|||||||
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files:     src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
 | 
					Files:     src/libosmo-mgcp-client/* include/osmocom/mgcp_client/*
 | 
				
			||||||
Copyright: 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
					Copyright: 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
           Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
					           Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
				
			||||||
           2009 by Harald Welte <laforge@gnumonks.org>
 | 
					           2009 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
           2009-2011 by Holger Hans Peter Freyther
 | 
					           2009-2011 by Holger Hans Peter Freyther
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								debian/postinst
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								debian/postinst
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#!/bin/sh -e
 | 
				
			||||||
 | 
					case "$1" in
 | 
				
			||||||
 | 
						configure)
 | 
				
			||||||
 | 
							# Create the osmocom group and user (if it doesn't exist yet)
 | 
				
			||||||
 | 
							if ! getent group osmocom >/dev/null; then
 | 
				
			||||||
 | 
								groupadd --system osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							if ! getent passwd osmocom >/dev/null; then
 | 
				
			||||||
 | 
								useradd \
 | 
				
			||||||
 | 
									--system \
 | 
				
			||||||
 | 
									--gid osmocom \
 | 
				
			||||||
 | 
									--home-dir /var/lib/osmocom \
 | 
				
			||||||
 | 
									--shell /sbin/nologin \
 | 
				
			||||||
 | 
									--comment "Open Source Mobile Communications" \
 | 
				
			||||||
 | 
									osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Fix permissions of previous (root-owned) install (OS#4107)
 | 
				
			||||||
 | 
							if dpkg --compare-versions "$2" le "1.13.0"; then
 | 
				
			||||||
 | 
								if [ -e /etc/osmocom/osmo-mgw.cfg ]; then
 | 
				
			||||||
 | 
									chown -v osmocom:osmocom /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
									chmod -v 0660 /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if [ -d /etc/osmocom ]; then
 | 
				
			||||||
 | 
									chown -v root:osmocom /etc/osmocom
 | 
				
			||||||
 | 
									chmod -v 2775 /etc/osmocom
 | 
				
			||||||
 | 
								fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								mkdir -p /var/lib/osmocom
 | 
				
			||||||
 | 
								chown -R -v osmocom:osmocom /var/lib/osmocom
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dh_installdeb(1) will replace this with shell code automatically
 | 
				
			||||||
 | 
					# generated by other debhelper scripts.
 | 
				
			||||||
 | 
					#DEBHELPER#
 | 
				
			||||||
							
								
								
									
										2
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -30,7 +30,7 @@ override_dh_auto_test:
 | 
				
			|||||||
	dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
 | 
						dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_auto_configure:
 | 
					override_dh_auto_configure:
 | 
				
			||||||
	dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
 | 
						dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
 | 
					# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
 | 
				
			||||||
override_dh_compress:
 | 
					override_dh_compress:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,25 @@
 | 
				
			|||||||
!
 | 
					!
 | 
				
			||||||
! MGCP configuration example
 | 
					! MGCP configuration example
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
 | 
					log stderr
 | 
				
			||||||
 | 
					 logging color 1
 | 
				
			||||||
 | 
					 logging print category-hex 0
 | 
				
			||||||
 | 
					 logging print category 1
 | 
				
			||||||
 | 
					 logging timestamp 0
 | 
				
			||||||
 | 
					 logging print file basename last
 | 
				
			||||||
 | 
					 logging print level 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
e1_input
 | 
					e1_input
 | 
				
			||||||
 e1_line 0 driver dahdi
 | 
					 e1_line 0 driver dahdi
 | 
				
			||||||
 e1_line 0 port 0
 | 
					 e1_line 0 port 0
 | 
				
			||||||
mgcp
 | 
					mgcp
 | 
				
			||||||
  bind ip 127.0.0.1
 | 
					  bind ip 127.0.0.1
 | 
				
			||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16001
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-dscp 46
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					 | 
				
			||||||
  sdp audio payload name GSM
 | 
					 | 
				
			||||||
  number endpoints 512
 | 
					  number endpoints 512
 | 
				
			||||||
  loop 0
 | 
					 | 
				
			||||||
  force-realloc 1
 | 
					  force-realloc 1
 | 
				
			||||||
  rtcp-omit
 | 
					  rtcp-omit
 | 
				
			||||||
  rtp-patch ssrc
 | 
					  rtp-patch ssrc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,22 @@
 | 
				
			|||||||
!
 | 
					!
 | 
				
			||||||
! MGCP configuration example
 | 
					! MGCP configuration example
 | 
				
			||||||
!
 | 
					!
 | 
				
			||||||
 | 
					log stderr
 | 
				
			||||||
 | 
					 logging color 1
 | 
				
			||||||
 | 
					 logging print category-hex 0
 | 
				
			||||||
 | 
					 logging print category 1
 | 
				
			||||||
 | 
					 logging timestamp 0
 | 
				
			||||||
 | 
					 logging print file basename last
 | 
				
			||||||
 | 
					 logging print level 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mgcp
 | 
					mgcp
 | 
				
			||||||
  bind ip 127.0.0.1
 | 
					  bind ip 127.0.0.1
 | 
				
			||||||
  rtp port-range 4002 16000
 | 
					  rtp port-range 4002 16001
 | 
				
			||||||
  rtp bind-ip 127.0.0.1
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
  rtp ip-probing
 | 
					  rtp ip-probing
 | 
				
			||||||
  rtp ip-dscp 46
 | 
					  rtp ip-dscp 46
 | 
				
			||||||
  bind port 2427
 | 
					  bind port 2427
 | 
				
			||||||
  sdp audio payload number 98
 | 
					 | 
				
			||||||
  sdp audio payload name GSM
 | 
					 | 
				
			||||||
  number endpoints 512
 | 
					  number endpoints 512
 | 
				
			||||||
  loop 0
 | 
					 | 
				
			||||||
  force-realloc 1
 | 
					  force-realloc 1
 | 
				
			||||||
  rtcp-omit
 | 
					  rtcp-omit
 | 
				
			||||||
  rtp-patch ssrc
 | 
					  rtp-patch ssrc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,4 +91,10 @@ encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
 | 
				
			|||||||
not yet useable.
 | 
					not yet useable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NOTE: the VTY command "show mgcp" can be used to get a list of all available
 | 
					NOTE: the VTY command "show mgcp" can be used to get a list of all available
 | 
				
			||||||
endpoints (including identifiers)
 | 
					endpoints (including identifiers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== The `null` endpoint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OsmoMGW offers a special `null@<domain>` endpoint which can be audited at all times.
 | 
				
			||||||
 | 
					This is useful for MGCP clients who wish to submit requests to OsmoMGW
 | 
				
			||||||
 | 
					periodically to find out whether it is still reachable and in a working state.
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,3 +23,20 @@ arguments:
 | 
				
			|||||||
	Disable colors for logging to stderr. This has mostly been
 | 
						Disable colors for logging to stderr. This has mostly been
 | 
				
			||||||
	deprecated by VTY based logging configuration, see <<logging>>
 | 
						deprecated by VTY based logging configuration, see <<logging>>
 | 
				
			||||||
	for more information.
 | 
						for more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== Configure limits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When servicing hundreds of media endpoints, it may be necessary to adjust the
 | 
				
			||||||
 | 
					operating system's limit on open file descriptors for the osmo-mgw process. A
 | 
				
			||||||
 | 
					typical default limit imposed by operating systems is 1024; this would be
 | 
				
			||||||
 | 
					exceeded by, for example, about 256 active voice calls with 4 RTP/RTPC ports
 | 
				
			||||||
 | 
					each, sockets for other interfaces not considered yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It should be ok to set an OS limit on open file descriptors as high as 65536
 | 
				
			||||||
 | 
					for osmo-mgw, which practically rules out failure from running out of file
 | 
				
			||||||
 | 
					descriptors anywhere (<16,000 active calls).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When using systemd, the file descriptor limit may be adjusted in the service
 | 
				
			||||||
 | 
					file by the `LimitNOFILE` setting ("Number of Open FILE descriptors"). OsmoMGW
 | 
				
			||||||
 | 
					ships a systemd service file with a high LimitNOFILE setting.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,14 @@ SUBDIRS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nobase_include_HEADERS = \
 | 
					nobase_include_HEADERS = \
 | 
				
			||||||
 | 
						osmocom/mgcp_client/defs.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client.h \
 | 
						osmocom/mgcp_client/mgcp_client.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
				
			||||||
 | 
						osmocom/mgcp_client/mgcp_client_pool.h \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	osmocom/mgcp/mgcp.h \
 | 
						osmocom/mgcp/mgcp.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_common.h \
 | 
						osmocom/mgcp/mgcp_common.h \
 | 
				
			||||||
	osmocom/mgcp/osmux.h \
 | 
						osmocom/mgcp/osmux.h \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,18 @@
 | 
				
			|||||||
noinst_HEADERS = \
 | 
					noinst_HEADERS = \
 | 
				
			||||||
	vty.h \
 | 
						vty.h \
 | 
				
			||||||
	mgcp_msg.h \
 | 
						mgcp_msg.h \
 | 
				
			||||||
 | 
						mgcp_codec.h \
 | 
				
			||||||
	mgcp_conn.h \
 | 
						mgcp_conn.h \
 | 
				
			||||||
	mgcp_stat.h \
 | 
						mgcp_stat.h \
 | 
				
			||||||
	mgcp_endp.h \
 | 
						mgcp_endp.h \
 | 
				
			||||||
	mgcp_sdp.h \
 | 
						mgcp_sdp.h \
 | 
				
			||||||
	mgcp_codec.h \
 | 
						mgcp_codec.h \
 | 
				
			||||||
	mgcp_ctrl.h \
 | 
					 | 
				
			||||||
	mgcp_trunk.h \
 | 
						mgcp_trunk.h \
 | 
				
			||||||
	debug.h \
 | 
						debug.h \
 | 
				
			||||||
	mgcp_ratectr.h \
 | 
						mgcp_ratectr.h \
 | 
				
			||||||
	mgcp_e1.h \
 | 
						mgcp_e1.h \
 | 
				
			||||||
	mgcp_network.h \
 | 
						mgcp_network.h \
 | 
				
			||||||
	mgcp_protocol.h \
 | 
						mgcp_protocol.h \
 | 
				
			||||||
 | 
						mgcp_iuup.h \
 | 
				
			||||||
 | 
						mgcp_rtp_end.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@
 | 
				
			|||||||
enum {
 | 
					enum {
 | 
				
			||||||
	DRTP,
 | 
						DRTP,
 | 
				
			||||||
	DE1,
 | 
						DE1,
 | 
				
			||||||
 | 
						DOSMUX,
 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,16 +24,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/write_queue.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#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,20 +65,16 @@ 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Return:
 | 
					 * Return:
 | 
				
			||||||
 *   <  0 in case no audio was processed
 | 
					 *   <  0 in case no audio was processed
 | 
				
			||||||
 *   >= 0 in case audio was processed. The remaining payload
 | 
					 *   >= 0 in case audio was processed.
 | 
				
			||||||
 *   length will be returned.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
 | 
					typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
 | 
				
			||||||
			       struct mgcp_rtp_end *dst_end,
 | 
								       struct mgcp_rtp_end *dst_end, struct msgb *msg);
 | 
				
			||||||
			       char *data, int *len, int buf_size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -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,16 +129,14 @@ 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;
 | 
				
			||||||
	mgcp_processing_setup setup_rtp_processing_cb;
 | 
						mgcp_processing_setup setup_rtp_processing_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_get_format get_net_downlink_format_cb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct osmo_wqueue gw_fd;
 | 
						struct osmo_wqueue gw_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mgcp_port_range net_ports;
 | 
						struct mgcp_port_range net_ports;
 | 
				
			||||||
@@ -147,37 +145,35 @@ struct mgcp_config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum mgcp_role role;
 | 
						enum mgcp_role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* osmux translator: 0 means disabled, 1 means enabled */
 | 
						struct {
 | 
				
			||||||
	int osmux;
 | 
							/* Osmux usage policy: */
 | 
				
			||||||
	/* addr to bind the server to */
 | 
							enum osmux_usage usage;
 | 
				
			||||||
	char *osmux_addr;
 | 
							/* addr to bind the server to */
 | 
				
			||||||
	/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
 | 
							char *local_addr_v4;
 | 
				
			||||||
	 * the osmux socket is already initialized.
 | 
							char *local_addr_v6;
 | 
				
			||||||
	 */
 | 
							/* osmux port */
 | 
				
			||||||
	int osmux_init;
 | 
							uint16_t local_port;
 | 
				
			||||||
	/* osmux batch factor: from 1 to 4 maximum */
 | 
							/* The osmux socket is allocated on demand (1st time used).
 | 
				
			||||||
	int osmux_batch;
 | 
							* This tells us if the osmux socket is already initialized.  */
 | 
				
			||||||
	/* osmux batch size (in bytes) */
 | 
							bool initialized;
 | 
				
			||||||
	int osmux_batch_size;
 | 
							/* osmux batch factor: from 1 to 4 maximum */
 | 
				
			||||||
	/* osmux port */
 | 
							int batch_factor;
 | 
				
			||||||
	uint16_t osmux_port;
 | 
							/* osmux batch size (in bytes) */
 | 
				
			||||||
	/* Pad circuit with dummy messages until we see the first voice
 | 
							int batch_size;
 | 
				
			||||||
	 * message.
 | 
							/* Pad circuit with dummy AMR frames if no payload to transmit is available */
 | 
				
			||||||
	 */
 | 
							bool dummy_padding;
 | 
				
			||||||
	uint16_t osmux_dummy;
 | 
							/* Whether peer is behind NAT (Retrieve remote addr from 1st received Osmux packet) */
 | 
				
			||||||
 | 
							bool peer_behind_nat;
 | 
				
			||||||
 | 
						} osmux;
 | 
				
			||||||
	/* domain name of the media gateway */
 | 
						/* domain name of the media gateway */
 | 
				
			||||||
	char domain[255+1];
 | 
						char domain[255+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -209,6 +205,5 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
 | 
				
			|||||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
					int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
					int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t prio);
 | 
				
			||||||
		     uint8_t prio);
 | 
					int mgcp_udp_send(struct osmo_io_fd *iofd, const struct osmo_sockaddr *addr, const char *buf, int len);
 | 
				
			||||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, char *buf, int len);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,9 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
					#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
				
			||||||
@@ -8,12 +12,37 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define PTYPE_UNDEFINED (-1)
 | 
					#define PTYPE_UNDEFINED (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_rtp_codec {
 | 
				
			||||||
 | 
						uint32_t rate;
 | 
				
			||||||
 | 
						int channels;
 | 
				
			||||||
 | 
						uint32_t frame_duration_num;
 | 
				
			||||||
 | 
						uint32_t frame_duration_den;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
						int payload_type;
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
						char audio_name[64];
 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
						char subtype_name[64];
 | 
				
			||||||
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);
 | 
						bool param_present;
 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_codecset {
 | 
				
			||||||
 | 
						/* currently selected audio codec */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
 | 
						/* array with assigned audio codecs to choose from (SDP) */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						/* number of assigned audio codecs (SDP) */
 | 
				
			||||||
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset);
 | 
				
			||||||
 | 
					void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str);
 | 
				
			||||||
 | 
					int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type,
 | 
				
			||||||
 | 
								    const char *audio_name, const struct mgcp_codec_param *param);
 | 
				
			||||||
 | 
					int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst);
 | 
				
			||||||
 | 
					const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@ enum mgcp_connection_mode {
 | 
				
			|||||||
	MGCP_CONN_SEND_ONLY = 2,
 | 
						MGCP_CONN_SEND_ONLY = 2,
 | 
				
			||||||
	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
 | 
						MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
 | 
				
			||||||
	MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
 | 
						MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
 | 
				
			||||||
 | 
						MGCP_CONN_CONFECHO  = 8 | MGCP_CONN_RECV_SEND,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
					#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
				
			||||||
@@ -67,11 +68,11 @@ struct mgcp_codec_param {
 | 
				
			|||||||
/* Ensure that the msg->l2h is NUL terminated. */
 | 
					/* Ensure that the msg->l2h is NUL terminated. */
 | 
				
			||||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
					static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
 | 
						unsigned char *tail = msg->tail; /* char after l2 data */
 | 
				
			||||||
	if (tail[-1] == '\0')
 | 
						if (tail[-1] == '\0')
 | 
				
			||||||
		/* nothing to do */;
 | 
							/* nothing to do */;
 | 
				
			||||||
	else if (msgb_tailroom(msg) > 0)
 | 
						else if (msgb_tailroom(msg) > 0)
 | 
				
			||||||
		tail[0] = '\0';
 | 
							msgb_put_u8(msg, (uint8_t)'\0');
 | 
				
			||||||
	else if (tail[-1] == '\r' || tail[-1] == '\n')
 | 
						else if (tail[-1] == '\r' || tail[-1] == '\n')
 | 
				
			||||||
		tail[-1] = '\0';
 | 
							tail[-1] = '\0';
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,10 +24,14 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
#include <osmocom/core/linuxlist.h>
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/iuup.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
@@ -45,9 +49,14 @@ LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
				
			|||||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
					/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
				
			||||||
enum mgcp_conn_rtp_type {
 | 
					enum mgcp_conn_rtp_type {
 | 
				
			||||||
	MGCP_RTP_DEFAULT	= 0,
 | 
						MGCP_RTP_DEFAULT	= 0,
 | 
				
			||||||
	MGCP_OSMUX_BSC,
 | 
						MGCP_RTP_OSMUX,
 | 
				
			||||||
	MGCP_OSMUX_BSC_NAT,
 | 
						MGCP_RTP_IUUP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					extern const struct value_string mgcp_conn_rtp_type_names[];
 | 
				
			||||||
 | 
					static inline const char *mgcp_conn_rtp_type_name(enum mgcp_conn_rtp_type val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return get_value_string(mgcp_conn_rtp_type_names, val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
 *  contains a useful connection description (currently only RTP) */
 | 
					 *  contains a useful connection description (currently only RTP) */
 | 
				
			||||||
@@ -78,22 +87,31 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* Osmux state: disabled, activating, active */
 | 
							/* Osmux state: disabled, activating, active */
 | 
				
			||||||
		enum osmux_state state;
 | 
							enum osmux_state state;
 | 
				
			||||||
		/* Is cid holding valid data? is it allocated from pool? */
 | 
							/* Is local_cid holding valid data? is it allocated from pool? */
 | 
				
			||||||
		bool cid_allocated;
 | 
							bool local_cid_allocated;
 | 
				
			||||||
		/* Allocated Osmux circuit ID for this conn */
 | 
							/* Allocated local Osmux circuit ID for this conn */
 | 
				
			||||||
		uint8_t cid;
 | 
							uint8_t local_cid;
 | 
				
			||||||
		/* handle to batch messages */
 | 
							/* Is remote_cid holding valid data? was it already received from client? */
 | 
				
			||||||
 | 
							bool remote_cid_present;
 | 
				
			||||||
 | 
							/* Received remote Osmux circuit ID for this conn */
 | 
				
			||||||
 | 
							uint8_t remote_cid;
 | 
				
			||||||
 | 
							/* handle to batch messages, shared (refcounted) among several conns */
 | 
				
			||||||
		struct osmux_in_handle *in;
 | 
							struct osmux_in_handle *in;
 | 
				
			||||||
		/* handle to unbatch messages */
 | 
							/* handle to unbatch messages, one allocated and owned per conn */
 | 
				
			||||||
		struct osmux_out_handle out;
 | 
							struct osmux_out_handle *out;
 | 
				
			||||||
		/* statistics */
 | 
							/* statistics: */
 | 
				
			||||||
		struct {
 | 
							struct rate_ctr_group *ctrg;
 | 
				
			||||||
			uint32_t chunks;
 | 
					 | 
				
			||||||
			uint32_t octets;
 | 
					 | 
				
			||||||
		} stats;
 | 
					 | 
				
			||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr_group *rate_ctr_group;
 | 
						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 *ctrg;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! MGCP connection (untyped) */
 | 
					/*! MGCP connection (untyped) */
 | 
				
			||||||
@@ -135,12 +153,12 @@ struct mgcp_conn {
 | 
				
			|||||||
enum {
 | 
					enum {
 | 
				
			||||||
	IN_STREAM_ERR_TSTMP_CTR,
 | 
						IN_STREAM_ERR_TSTMP_CTR,
 | 
				
			||||||
	OUT_STREAM_ERR_TSTMP_CTR,
 | 
						OUT_STREAM_ERR_TSTMP_CTR,
 | 
				
			||||||
        RTP_PACKETS_RX_CTR,
 | 
						RTP_PACKETS_RX_CTR,
 | 
				
			||||||
        RTP_OCTETS_RX_CTR,
 | 
						RTP_OCTETS_RX_CTR,
 | 
				
			||||||
        RTP_PACKETS_TX_CTR,
 | 
						RTP_PACKETS_TX_CTR,
 | 
				
			||||||
        RTP_OCTETS_TX_CTR,
 | 
						RTP_OCTETS_TX_CTR,
 | 
				
			||||||
        RTP_DROPPED_PACKETS_CTR,
 | 
						RTP_DROPPED_PACKETS_CTR,
 | 
				
			||||||
        RTP_NUM_CONNECTIONS,
 | 
						RTP_NUM_CONNECTIONS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
					/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
				
			||||||
@@ -153,7 +171,7 @@ static const struct rate_ctr_desc mgcp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
						[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
				
			||||||
	[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
						[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
				
			||||||
	[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
						[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
				
			||||||
	[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "dropped rtp packets."}
 | 
						[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "Dropped rtp packets."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
					/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
				
			||||||
@@ -171,20 +189,67 @@ static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
						[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Osmux connection related counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						OSMUX_CHUNKS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_OCTETS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_RTP_PACKETS_TX_CTR,
 | 
				
			||||||
 | 
						OSMUX_RTP_PACKETS_TX_DROPPED_CTR,
 | 
				
			||||||
 | 
						OSMUX_AMR_OCTETS_TX_CTR,
 | 
				
			||||||
 | 
						/* Only available in global stats: */
 | 
				
			||||||
 | 
						OSMUX_NUM_CONNECTIONS,
 | 
				
			||||||
 | 
						OSMUX_PACKETS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_PACKETS_TX_CTR,
 | 
				
			||||||
 | 
						OSMUX_DROPPED_PACKETS_CTR,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
				
			||||||
 | 
					 * exist for the lifetime of an RTP connection.
 | 
				
			||||||
 | 
					 * Must be kept in sync with all_rtp_conn_rate_ctr_desc below */
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_conn_osmux_rate_ctr_desc[] = {
 | 
				
			||||||
 | 
						[OSMUX_CHUNKS_RX_CTR] = {"osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
				
			||||||
 | 
						[OSMUX_OCTETS_RX_CTR] = {"osmux:octets_rx", "Inbound Osmux octets."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_CTR] = {"osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_AMR_OCTETS_TX_CTR] = {"osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Aggregated Osmux connection stats. These are updated when an Osmux connection is freed.
 | 
				
			||||||
 | 
					 * Must be kept in sync with mgcp_conn_osmux_rate_ctr_desc above */
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc all_osmux_conn_rate_ctr_desc[] = {
 | 
				
			||||||
 | 
						[OSMUX_CHUNKS_RX_CTR] = {"all_osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
				
			||||||
 | 
						[OSMUX_OCTETS_RX_CTR] = {"all_osmux:octets_rx", "Inbound Osmux octets."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_CTR] = {"all_osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"all_osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_AMR_OCTETS_TX_CTR] = {"all_osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
				
			||||||
 | 
						/* These last counters below do not exist in per-connection stats, only here: */
 | 
				
			||||||
 | 
						[OSMUX_NUM_CONNECTIONS] = {"all_osmux:num_closed_conns", "Total number of osmux connections closed."},
 | 
				
			||||||
 | 
						[OSMUX_PACKETS_RX_CTR] = {"all_osmux:packets_rx", "Total inbound UDP/Osmux packets."},
 | 
				
			||||||
 | 
						[OSMUX_PACKETS_TX_CTR] = {"all_osmux:packets_tx", "Total outbound UDP/Osmux packets."},
 | 
				
			||||||
 | 
						[OSMUX_DROPPED_PACKETS_CTR] = {"all_osmux:dropped_packets", "Dropped outbound UDP/Osmux packets."}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
					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_RTP_OSMUX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP);
 | 
				
			||||||
 | 
						return &conn->u.rtp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
					struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			||||||
				  enum mgcp_conn_type type, char *name);
 | 
									  enum mgcp_conn_type type, char *name);
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
 | 
					void mgcp_conn_free(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
					int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode);
 | 
				
			||||||
					const char *id);
 | 
					 | 
				
			||||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
 | 
					 | 
				
			||||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
					char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
 | 
					struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,5 +23,5 @@ static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
 | 
					int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
 | 
				
			||||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts);
 | 
				
			||||||
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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
@@ -39,8 +40,13 @@ LOGP(cat, level, "endpoint:%s " fmt, \
 | 
				
			|||||||
     endp ? endp->name : "none", \
 | 
					     endp ? endp->name : "none", \
 | 
				
			||||||
     ## args)
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum rtp_proto {
 | 
				
			||||||
 | 
						MGCP_PROTO_RTP,
 | 
				
			||||||
 | 
						MGCP_PROTO_RTCP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct osmo_rtp_msg_ctx {
 | 
					struct osmo_rtp_msg_ctx {
 | 
				
			||||||
	int proto;
 | 
						enum rtp_proto proto;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_src;
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
	struct osmo_sockaddr *from_addr;
 | 
						struct osmo_sockaddr *from_addr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -96,9 +102,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 +114,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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,13 +130,28 @@ struct mgcp_endpoint {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
 | 
					struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
					 | 
				
			||||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
					int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					bool mgcp_endp_is_wildcarded(const char *epname);
 | 
				
			||||||
 | 
					bool mgcp_endp_is_null(const char *epname);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			||||||
					      const struct mgcp_trunk *trunk);
 | 
										      const struct mgcp_trunk *trunk);
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			||||||
					struct mgcp_config *cfg);
 | 
										struct mgcp_config *cfg);
 | 
				
			||||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
 | 
					bool mgcp_endp_avail(const struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					bool mgcp_endp_is_full(const struct mgcp_endpoint *endp);
 | 
				
			||||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
 | 
				
			||||||
 | 
								 const struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
				
			||||||
 | 
								const struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id);
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										const char *id);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,11 @@
 | 
				
			|||||||
 | 
					/* IuUP connection functionalitites */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
					 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Pau Espin Pedrol
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
@@ -16,9 +20,14 @@
 | 
				
			|||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
                                             const char *bind_addr, uint16_t port);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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,21 +25,25 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
struct mgcp_parse_data;
 | 
					struct mgcp_parse_data;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					struct mgcp_trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
 | 
					void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
 | 
					enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg);
 | 
				
			||||||
			 struct mgcp_conn *conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
					int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
 | 
				
			||||||
 | 
					int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_osmux_cid(const char *line);
 | 
					int mgcp_parse_osmux_cid(const char *line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
 | 
					bool mgcp_check_param(const char *line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
 | 
					int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,21 @@
 | 
				
			|||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The following constant defines an RTP dummy payload that is used for
 | 
				
			||||||
 | 
					 * "UDP Hole Punching" (NAT) */
 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					#define MGCP_DUMMY_LOAD 0x23
 | 
				
			||||||
 | 
					static const char rtp_dummy_payload[] = { MGCP_DUMMY_LOAD };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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 +36,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,66 +72,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 {
 | 
					 | 
				
			||||||
	uint32_t rate;
 | 
					 | 
				
			||||||
	int channels;
 | 
					 | 
				
			||||||
	uint32_t frame_duration_num;
 | 
					 | 
				
			||||||
	uint32_t frame_duration_den;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int payload_type;
 | 
					 | 
				
			||||||
	char *audio_name;
 | 
					 | 
				
			||||||
	char *subtype_name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool param_present;
 | 
					 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
					 | 
				
			||||||
struct mgcp_rtp_end {
 | 
					 | 
				
			||||||
	/* remote IP address of the RTP socket */
 | 
					 | 
				
			||||||
	struct osmo_sockaddr addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* in network byte order */
 | 
					 | 
				
			||||||
	int rtp_port, rtcp_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* currently selected audio codec */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* array with assigned audio codecs to choose from (SDP) */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* number of assigned audio codecs (SDP) */
 | 
					 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* per endpoint data */
 | 
					 | 
				
			||||||
	int  frames_per_packet;
 | 
					 | 
				
			||||||
	uint32_t packet_duration_ms;
 | 
					 | 
				
			||||||
	int maximum_packet_time; /* -1: not set */
 | 
					 | 
				
			||||||
	char *fmtp_extra;
 | 
					 | 
				
			||||||
	/* are we transmitting packets (1) or dropping (0) outbound packets */
 | 
					 | 
				
			||||||
	int output_enabled;
 | 
					 | 
				
			||||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
					 | 
				
			||||||
	int force_output_ptime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* RTP patching */
 | 
					 | 
				
			||||||
	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
 | 
					 | 
				
			||||||
	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
					 | 
				
			||||||
	int force_aligned_timing;
 | 
					 | 
				
			||||||
	bool rfc5993_hr_convert;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Each end has a separate socket for RTP and RTCP */
 | 
					 | 
				
			||||||
	struct osmo_fd rtp;
 | 
					 | 
				
			||||||
	struct osmo_fd rtcp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
					 | 
				
			||||||
	int local_port;
 | 
					 | 
				
			||||||
	/* where the endpoint RTP connection binds to, set during CRCX and
 | 
					 | 
				
			||||||
	 * possibly updated during MDCX */
 | 
					 | 
				
			||||||
	char local_addr[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_tap {
 | 
					struct mgcp_rtp_tap {
 | 
				
			||||||
@@ -140,18 +91,15 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
 | 
				
			|||||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
 | 
					int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
 | 
				
			||||||
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
					int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port);
 | 
				
			||||||
			   struct mgcp_conn_rtp *conn);
 | 
					void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			||||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
 | 
					 | 
				
			||||||
void mgcp_patch_and_count(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);
 | 
					int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* payload processing default functions */
 | 
					/* payload processing default functions */
 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct msgb *msg);
 | 
				
			||||||
				char *data, int *len, int buf_size);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
					int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
				      struct mgcp_conn_rtp *conn_dst,
 | 
									      struct mgcp_conn_rtp *conn_dst,
 | 
				
			||||||
@@ -163,6 +111,15 @@ 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 rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									 int id);
 | 
				
			||||||
 | 
					void forward_data_tap(struct osmo_io_fd *iofd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
				
			||||||
 | 
					uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,73 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_PTIME_UNSET (-1)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_SDP_RTP_PORT_UNSET (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_parse_sdp {
 | 
				
			||||||
 | 
						int ptime;
 | 
				
			||||||
 | 
						int maxptime;
 | 
				
			||||||
 | 
						int rtp_port;
 | 
				
			||||||
 | 
						struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */
 | 
				
			||||||
 | 
						struct mgcp_rtp_codecset cset;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET;
 | 
				
			||||||
 | 
						sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET;
 | 
				
			||||||
 | 
						sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET;
 | 
				
			||||||
 | 
						sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC };
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&sdp->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2)
 | 
				
			||||||
 | 
					#define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_parse_hdr_pars {
 | 
				
			||||||
 | 
						const char *local_options;
 | 
				
			||||||
 | 
						const char *callid;
 | 
				
			||||||
 | 
						const char *connid;
 | 
				
			||||||
 | 
						enum mgcp_connection_mode mode;
 | 
				
			||||||
 | 
						int remote_osmux_cid;
 | 
				
			||||||
 | 
						bool have_sdp;
 | 
				
			||||||
 | 
						/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
				
			||||||
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*hpars = (struct mgcp_parse_hdr_pars){
 | 
				
			||||||
 | 
							.local_options = NULL,
 | 
				
			||||||
 | 
							.callid = NULL,
 | 
				
			||||||
 | 
							.connid = NULL,
 | 
				
			||||||
 | 
							.mode = MGCP_CONN_NONE,
 | 
				
			||||||
 | 
							.remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET,
 | 
				
			||||||
 | 
							.have_sdp = false,
 | 
				
			||||||
 | 
							.x_osmo_ign = 0,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Internal structure while parsing a request */
 | 
					/* Internal structure while parsing a request */
 | 
				
			||||||
struct mgcp_parse_data {
 | 
					struct mgcp_parse_data {
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	char *trans;
 | 
					 | 
				
			||||||
	char *save;
 | 
						char *save;
 | 
				
			||||||
 | 
						/* MGCP Header: */
 | 
				
			||||||
 | 
						char *epname;
 | 
				
			||||||
 | 
						char *trans;
 | 
				
			||||||
 | 
						struct mgcp_parse_hdr_pars hpars;
 | 
				
			||||||
 | 
						/* MGCP Body: */
 | 
				
			||||||
 | 
						struct mgcp_parse_sdp sdp;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Local connection options */
 | 
					/* Local connection options */
 | 
				
			||||||
@@ -16,12 +78,19 @@ 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;
 | 
				
			||||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
			 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string mgcp_connection_mode_strs[];
 | 
				
			||||||
 | 
					static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return get_value_string(mgcp_connection_mode_strs, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,9 +80,30 @@ struct mgcp_ratectr_trunk {
 | 
				
			|||||||
	struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
						struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
				
			||||||
	/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
						/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
				
			||||||
	struct rate_ctr_group *all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_rtp_conn_stats;
 | 
				
			||||||
 | 
						/* Rate counter group which aggregates stats of individual Osmux connections. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *all_osmux_conn_stats;
 | 
				
			||||||
	/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
						/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
				
			||||||
	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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
				
			||||||
 | 
					struct mgcp_rtp_end {
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp; /* backpointer */
 | 
				
			||||||
 | 
						/* remote IP address of the RTP socket */
 | 
				
			||||||
 | 
						struct osmo_sockaddr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* in network byte order */
 | 
				
			||||||
 | 
						uint16_t rtcp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mgcp_rtp_codecset cset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* per endpoint data */
 | 
				
			||||||
 | 
						int  frames_per_packet;
 | 
				
			||||||
 | 
						uint32_t packet_duration_ms;
 | 
				
			||||||
 | 
						int maximum_packet_time; /* -1: not set */
 | 
				
			||||||
 | 
						/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
				
			||||||
 | 
						bool output_enabled;
 | 
				
			||||||
 | 
						/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
				
			||||||
 | 
						int force_output_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* RTP patching */
 | 
				
			||||||
 | 
						bool force_constant_ssrc;
 | 
				
			||||||
 | 
						/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
				
			||||||
 | 
						int force_aligned_timing;
 | 
				
			||||||
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Each end has a separate socket for RTP and RTCP */
 | 
				
			||||||
 | 
						struct osmo_io_fd *rtp;
 | 
				
			||||||
 | 
						struct osmo_io_fd *rtcp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
				
			||||||
 | 
						int local_port;
 | 
				
			||||||
 | 
						/* where the endpoint RTP connection binds to, set during CRCX and
 | 
				
			||||||
 | 
						 * possibly updated during MDCX */
 | 
				
			||||||
 | 
						char local_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms);
 | 
				
			||||||
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
 | 
				
			||||||
 | 
					void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end);
 | 
				
			||||||
@@ -22,9 +22,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
					struct mgcp_parse_data;
 | 
				
			||||||
			struct mgcp_conn_rtp *conn,
 | 
					
 | 
				
			||||||
			struct mgcp_parse_data *p);
 | 
					int mgcp_parse_sdp_data(struct mgcp_parse_data *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
					int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			||||||
			    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
								    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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,37 +2,40 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/gsm/i460_mux.h>
 | 
					#include <osmocom/gsm/i460_mux.h>
 | 
				
			||||||
#include <osmocom/abis/e1_input.h>
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
	int audio_send_ptime;
 | 
						int audio_send_ptime;
 | 
				
			||||||
	int audio_send_name;
 | 
						int audio_send_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int no_audio_transcoding;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int omit_rtcp;
 | 
						int omit_rtcp;
 | 
				
			||||||
	int keepalive_interval;
 | 
						int keepalive_interval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RTP patching */
 | 
						/* RTP patching */
 | 
				
			||||||
	int force_constant_ssrc; /* 0: don't, 1: once */
 | 
						bool force_constant_ssrc;
 | 
				
			||||||
	int force_aligned_timing;
 | 
						int force_aligned_timing;
 | 
				
			||||||
	bool rfc5993_hr_convert;
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,8 +52,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 */
 | 
				
			||||||
@@ -60,7 +64,7 @@ struct mgcp_trunk {
 | 
				
			|||||||
		/* E1 specific */
 | 
							/* E1 specific */
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			unsigned int vty_line_nr;
 | 
								unsigned int vty_line_nr;
 | 
				
			||||||
			bool ts_in_use[NUM_E1_TS-1];
 | 
								uint8_t ts_usecount[NUM_E1_TS-1];
 | 
				
			||||||
			struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
 | 
								struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
 | 
				
			||||||
			/* Note: on an E1 line TS 0 is devoted to framing and
 | 
								/* Note: on an E1 line TS 0 is devoted to framing and
 | 
				
			||||||
			 * alignment and therefore only NUM_E1_TS-1 timeslots
 | 
								 * alignment and therefore only NUM_E1_TS-1 timeslots
 | 
				
			||||||
@@ -69,12 +73,13 @@ 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);
 | 
				
			||||||
 | 
					int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
					/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
				
			||||||
 * use this define constant as ID when allocating a virtual trunk. Other
 | 
					 * use this define constant as ID when allocating a virtual trunk. Other
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,22 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					struct mgcp_trunk;
 | 
				
			||||||
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define OSMUX_PORT	1984
 | 
					int osmux_init(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					int osmux_init_conn(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
enum {
 | 
					int conn_osmux_enable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
	OSMUX_ROLE_BSC = 0,
 | 
					 | 
				
			||||||
	OSMUX_ROLE_BSC_NAT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int osmux_init(int role, struct mgcp_config *cfg);
 | 
					 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					 | 
				
			||||||
		      struct osmo_sockaddr *addr, uint16_t port);
 | 
					 | 
				
			||||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
 | 
					int conn_osmux_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
					int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg);
 | 
				
			||||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
 | 
					int osmux_send_dummy(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
					void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
				
			||||||
int osmux_cid_pool_get_next(void);
 | 
					int osmux_cid_pool_get_next(void);
 | 
				
			||||||
@@ -29,10 +26,14 @@ int osmux_cid_pool_count_used(void);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum osmux_state {
 | 
					enum osmux_state {
 | 
				
			||||||
	OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
						OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
				
			||||||
	OSMUX_STATE_ACTIVATING,   /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref osmux_enable_endpoint. */
 | 
						OSMUX_STATE_ACTIVATING,   /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref conn_osmux_enable. */
 | 
				
			||||||
	OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
 | 
						OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref conn_osmux_enable and can process frames */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string osmux_state_strs[];
 | 
				
			||||||
 | 
					static inline const char *osmux_state_str(enum osmux_state val)
 | 
				
			||||||
 | 
					{ return get_value_string(osmux_state_strs, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum osmux_usage {
 | 
					enum osmux_usage {
 | 
				
			||||||
	OSMUX_USAGE_OFF = 0,
 | 
						OSMUX_USAGE_OFF = 0,
 | 
				
			||||||
	OSMUX_USAGE_ON = 1,
 | 
						OSMUX_USAGE_ON = 1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								include/osmocom/mgcp_client/defs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								include/osmocom/mgcp_client/defs.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#include <osmocom/core/defs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if BUILDING_LIBOSMOMGCPCLIENT
 | 
				
			||||||
 | 
					# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT(text) OSMO_DEPRECATED(text)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -3,14 +3,15 @@
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/defs.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_common.h>
 | 
					#include <osmocom/mgcp_client/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
					/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
					#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
 | 
					#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
					#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
					#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
				
			||||||
 | 
					#define MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP "null"
 | 
				
			||||||
#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
 | 
					#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb;
 | 
					struct msgb;
 | 
				
			||||||
@@ -26,6 +27,21 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							uint32_t timeout_sec;
 | 
				
			||||||
 | 
							uint32_t req_interval_sec;
 | 
				
			||||||
 | 
							char req_endpoint_name[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						} keepalive;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef unsigned int mgcp_trans_id_t;
 | 
					typedef unsigned int mgcp_trans_id_t;
 | 
				
			||||||
@@ -36,10 +52,12 @@ enum mgcp_codecs {
 | 
				
			|||||||
	CODEC_GSM_8000_1 = 3,
 | 
						CODEC_GSM_8000_1 = 3,
 | 
				
			||||||
	CODEC_PCMA_8000_1 = 8,
 | 
						CODEC_PCMA_8000_1 = 8,
 | 
				
			||||||
	CODEC_G729_8000_1 = 18,
 | 
						CODEC_G729_8000_1 = 18,
 | 
				
			||||||
	CODEC_GSMEFR_8000_1 = 110,
 | 
						CODEC_GSMEFR_8000_1 = 110,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
	CODEC_GSMHR_8000_1 = 111,
 | 
						CODEC_GSMHR_8000_1 = 111,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
	CODEC_AMR_8000_1 = 112,
 | 
						CODEC_AMR_8000_1 = 112,		/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
	CODEC_AMRWB_16000_1 = 113,
 | 
						CODEC_AMRWB_16000_1 = 113,	/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
 | 
						CODEC_IUFP = 96,
 | 
				
			||||||
 | 
						CODEC_CLEARMODE = 120,		/* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
/* 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
 | 
				
			||||||
@@ -61,27 +79,7 @@ struct ptmap {
 | 
				
			|||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_head {
 | 
					int ptmap_cmp(const struct ptmap *a, const struct ptmap *b);
 | 
				
			||||||
	int response_code;
 | 
					 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
					 | 
				
			||||||
	char comment[MGCP_COMMENT_MAXLEN];
 | 
					 | 
				
			||||||
	char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
					 | 
				
			||||||
	char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	bool x_osmo_osmux_use;
 | 
					 | 
				
			||||||
	uint8_t x_osmo_osmux_cid;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_response {
 | 
					 | 
				
			||||||
	char *body;
 | 
					 | 
				
			||||||
	struct mgcp_response_head head;
 | 
					 | 
				
			||||||
	uint16_t audio_port;
 | 
					 | 
				
			||||||
	char audio_ip[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
	unsigned int ptime;
 | 
					 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int codecs_len;
 | 
					 | 
				
			||||||
	struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int ptmap_len;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum mgcp_verb {
 | 
					enum mgcp_verb {
 | 
				
			||||||
	MGCP_VERB_CRCX,
 | 
						MGCP_VERB_CRCX,
 | 
				
			||||||
@@ -91,38 +89,8 @@ enum mgcp_verb {
 | 
				
			|||||||
	MGCP_VERB_RSIP,
 | 
						MGCP_VERB_RSIP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_ENDPOINT	0x0001
 | 
					struct mgcp_client_conf *mgcp_client_conf_alloc(void *ctx);
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CALL_ID	0x0002
 | 
					void mgcp_client_conf_init(struct mgcp_client_conf *conf) OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use mgcp_client_conf_alloc() (or even better, switch to the mgcp_client_pool API!)");
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CONN_ID	0x0004
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
 | 
					 | 
				
			||||||
#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_msg {
 | 
					 | 
				
			||||||
	enum mgcp_verb verb;
 | 
					 | 
				
			||||||
	/* See MGCP_MSG_PRESENCE_* constants */
 | 
					 | 
				
			||||||
	uint32_t presence;
 | 
					 | 
				
			||||||
	char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
					 | 
				
			||||||
	unsigned int call_id;
 | 
					 | 
				
			||||||
	char *conn_id;
 | 
					 | 
				
			||||||
	uint16_t audio_port;
 | 
					 | 
				
			||||||
	char *audio_ip;
 | 
					 | 
				
			||||||
	enum mgcp_connection_mode conn_mode;
 | 
					 | 
				
			||||||
	unsigned int ptime;
 | 
					 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int codecs_len;
 | 
					 | 
				
			||||||
	struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
					 | 
				
			||||||
	unsigned int ptmap_len;
 | 
					 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
					 | 
				
			||||||
	bool x_osmo_osmux_use;
 | 
					 | 
				
			||||||
	int x_osmo_osmux_cid; /* -1 is wildcard */
 | 
					 | 
				
			||||||
	bool param_present;
 | 
					 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
 | 
					 | 
				
			||||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
 | 
					void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent);
 | 
					int mgcp_client_config_write(struct vty *vty, const char *indent);
 | 
				
			||||||
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
					struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
				
			||||||
@@ -130,6 +98,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) OSMO_DEPRECATED("Use mgcp_client_connect() instead");
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
@@ -140,20 +110,8 @@ const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
 | 
				
			|||||||
const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
					const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
				
			||||||
				  uint8_t rate, uint8_t offset);
 | 
									  uint8_t rate, uint8_t offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Invoked when an MGCP response is received or sending failed.  When the
 | 
					 | 
				
			||||||
 * response is passed as NULL, this indicates failure during transmission. */
 | 
					 | 
				
			||||||
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
 | 
					 | 
				
			||||||
int mgcp_response_parse_params(struct mgcp_response *r);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
					 | 
				
			||||||
		   mgcp_response_cb_t response_cb, void *priv);
 | 
					 | 
				
			||||||
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum mgcp_connection_mode;
 | 
					enum mgcp_connection_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
 | 
					 | 
				
			||||||
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern const struct value_string mgcp_client_connection_mode_strs[];
 | 
					extern const struct value_string mgcp_client_connection_mode_strs[];
 | 
				
			||||||
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
 | 
					static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -165,3 +123,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,
 | 
				
			||||||
@@ -43,8 +45,10 @@ static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			|||||||
void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
					void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
					const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
					const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,11 @@ struct mgcp_conn_peer {
 | 
				
			|||||||
	/*! RTP packetization interval (optional) */
 | 
						/*! RTP packetization interval (optional) */
 | 
				
			||||||
	unsigned int ptime;
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! RTP codec list (optional) */
 | 
						/*! Deprecated. Use only ptmap[].codec in new code. */
 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
						enum mgcp_codecs codecs[MGCP_MAX_CODECS]
 | 
				
			||||||
 | 
							OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[i].codec instead");
 | 
				
			||||||
	/*! Number of codecs in RTP codec list (optional) */
 | 
						unsigned int codecs_len
 | 
				
			||||||
	unsigned int codecs_len;
 | 
							OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use ptmap[] and ptmap_len instead");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! RTP payload type map (optional, only needed when payload types are
 | 
						/*! RTP payload type map (optional, only needed when payload types are
 | 
				
			||||||
	 * used that differ from what IANA/3GPP defines) */
 | 
						 * used that differ from what IANA/3GPP defines) */
 | 
				
			||||||
@@ -64,10 +64,15 @@ struct mgcp_conn_peer {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
					struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
				
			||||||
				       uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
 | 
									       uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer);
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_alloc() and osmo_mgcpc_ep_ci_add() instead");
 | 
				
			||||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
					int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_request() instead");
 | 
				
			||||||
 | 
					void mgcp_conn_delete(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci_dlcx() instead");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
 | 
					const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
						OSMO_DEPRECATED_OUTSIDE_LIBOSMOMGCPCLIENT("use osmo_mgcpc_ep_ci.mgcp_ci_str instead");
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
 | 
					const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,53 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MSGB_CB_MGCP_TRANS_ID 0
 | 
					#define MSGB_CB_MGCP_TRANS_ID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client {
 | 
					/* Struct that holds one endpoint name */
 | 
				
			||||||
	struct mgcp_client_conf actual;
 | 
					struct reset_ep {
 | 
				
			||||||
	struct osmo_wqueue wq;
 | 
						struct llist_head list;
 | 
				
			||||||
	mgcp_trans_id_t next_trans_id;
 | 
						char name[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
					 | 
				
			||||||
	struct llist_head inuse_endpoints;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_inuse_endpoint {
 | 
					struct mgcp_client {
 | 
				
			||||||
	struct llist_head entry;
 | 
						struct mgcp_client_conf actual;
 | 
				
			||||||
	uint16_t id;
 | 
						struct osmo_io_fd *iofd;
 | 
				
			||||||
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						struct osmo_timer_list keepalive_tx_timer;
 | 
				
			||||||
 | 
						struct osmo_timer_list keepalive_rx_timer;
 | 
				
			||||||
 | 
						bool conn_up;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_response_head {
 | 
				
			||||||
 | 
						int response_code;
 | 
				
			||||||
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
 | 
						char comment[MGCP_COMMENT_MAXLEN];
 | 
				
			||||||
 | 
						char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
				
			||||||
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						uint8_t x_osmo_osmux_cid;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_response {
 | 
				
			||||||
 | 
						char *body;
 | 
				
			||||||
 | 
						struct mgcp_response_head head;
 | 
				
			||||||
 | 
						uint16_t audio_port;
 | 
				
			||||||
 | 
						char audio_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Invoked when an MGCP response is received or sending failed.  When the
 | 
				
			||||||
 | 
					 * response is passed as NULL, this indicates failure during transmission. */
 | 
				
			||||||
 | 
					typedef void (*mgcp_response_cb_t)(struct mgcp_response *response, void *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending {
 | 
					struct mgcp_response_pending {
 | 
				
			||||||
	struct llist_head entry;
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,3 +63,41 @@ struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			|||||||
					mgcp_trans_id_t trans_id,
 | 
										mgcp_trans_id_t trans_id,
 | 
				
			||||||
					mgcp_response_cb_t response_cb,
 | 
										mgcp_response_cb_t response_cb,
 | 
				
			||||||
					void *priv);
 | 
										void *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_ENDPOINT	0x0001
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CALL_ID	0x0002
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CONN_ID	0x0004
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_msg {
 | 
				
			||||||
 | 
						enum mgcp_verb verb;
 | 
				
			||||||
 | 
						/* See MGCP_MSG_PRESENCE_* constants */
 | 
				
			||||||
 | 
						uint32_t presence;
 | 
				
			||||||
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						unsigned int call_id;
 | 
				
			||||||
 | 
						char *conn_id;
 | 
				
			||||||
 | 
						uint16_t audio_port;
 | 
				
			||||||
 | 
						char *audio_ip;
 | 
				
			||||||
 | 
						enum mgcp_connection_mode conn_mode;
 | 
				
			||||||
 | 
						unsigned int ptime;
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						int x_osmo_osmux_cid; /* -1 is wildcard */
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_response_parse_params(struct mgcp_response *r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			||||||
 | 
							   mgcp_response_cb_t response_cb, void *priv);
 | 
				
			||||||
 | 
					int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
 | 
				
			||||||
 | 
					mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								include/osmocom/mgcp_client/mgcp_client_pool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								include/osmocom/mgcp_client/mgcp_client_pool.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/vty/vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client;
 | 
				
			||||||
 | 
					struct mgcp_client_pool;
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr);
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 | 
					bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
							
								
								
									
										52
									
								
								include/osmocom/mgcp_client/mgcp_client_pool_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								include/osmocom/mgcp_client/mgcp_client_pool_internal.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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 mgcp_client_pool_member->list above) */
 | 
				
			||||||
 | 
						struct llist_head member_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Struct to handle a member of a pool of MGWs. */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member {
 | 
				
			||||||
 | 
						/* Entry in llist mgcp_client_pool->pool. */
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The pool managing this object: */
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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 mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr);
 | 
				
			||||||
 | 
					void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 | 
					int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 | 
					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
 | 
					 | 
				
			||||||
@@ -13,12 +13,6 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(COVERAGE_CFLAGS) \
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOGSM_LIBS) \
 | 
					 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Libraries
 | 
					# Libraries
 | 
				
			||||||
SUBDIRS = \
 | 
					SUBDIRS = \
 | 
				
			||||||
	libosmo-mgcp-client \
 | 
						libosmo-mgcp-client \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,14 +14,12 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOVTY_LIBS) \
 | 
					 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# This is not at all related to the release version, but a range of supported
 | 
					# This is not at all related to the release version, but a range of supported
 | 
				
			||||||
# API versions. Read TODO_RELEASE in the source tree's root!
 | 
					# API versions. Read TODO_RELEASE in the source tree's root!
 | 
				
			||||||
MGCP_CLIENT_LIBVERSION=8:0:0
 | 
					MGCP_CLIENT_LIBVERSION=14:1:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -32,6 +30,16 @@ 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) \
 | 
				
			||||||
 | 
						-no-undefined \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libosmo_mgcp_client_la_LIBADD = \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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), \
 | 
				
			||||||
@@ -173,6 +173,30 @@ const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
 | 
				
			|||||||
	return osmo_fsm_inst_name(ep->fi);
 | 
						return osmo_fsm_inst_name(ep->fi);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get "local endpoint name" part of the endpoint name: (local-endpoint-name@domain-name)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param ep  The MGCP Endpoint
 | 
				
			||||||
 | 
					 * \returns the local endpoint name if found, NULL on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_local_name(const struct osmo_mgcpc_ep *ep)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char buf[1024];
 | 
				
			||||||
 | 
						const char *sep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ep);
 | 
				
			||||||
 | 
						sep = strchr(ep->endpoint, '@');
 | 
				
			||||||
 | 
						if (!sep) {
 | 
				
			||||||
 | 
							OSMO_STRLCPY_ARRAY(buf, ep->endpoint);
 | 
				
			||||||
 | 
							return buf;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (sep - ep->endpoint >= sizeof(buf))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(buf, ep->endpoint, sep - ep->endpoint);
 | 
				
			||||||
 | 
						buf[sep - ep->endpoint] = '\0';
 | 
				
			||||||
 | 
						return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
					const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
						/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
				
			||||||
@@ -216,11 +240,18 @@ 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] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fill_event_names()
 | 
					static void fill_event_names(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
						for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
				
			||||||
@@ -236,7 +267,7 @@ static void fill_event_names()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
					static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
				
			||||||
	fill_event_names();
 | 
						fill_event_names();
 | 
				
			||||||
@@ -502,13 +533,46 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			|||||||
	       mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
 | 
						       mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
 | 
				
			||||||
	       ci->notify.fi ? "" : " (not sending a notification)");
 | 
						       ci->notify.fi ? "" : " (not sending a notification)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Below ordering is a delicate decision:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We want to
 | 
				
			||||||
 | 
						 * - emit the resulting event to ci->notify.fi,
 | 
				
			||||||
 | 
						 * - check whether we want to tx the next pending MGCP message.
 | 
				
			||||||
 | 
						 * Both these steps may terminate (=deallocate) the ep.
 | 
				
			||||||
 | 
						 * So whichever one goes first may cause a use-after-free in the other.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * When dispatching the FSM event, we don't get an rc indicating dealloc of the FSM -- it may deallocate and we
 | 
				
			||||||
 | 
						 * cannot tell. The common mechanism for that is osmo_fsm_set_dealloc_ctx(OTC_SELECT) and query the still
 | 
				
			||||||
 | 
						 * allocated FSM state after termination (here we would check 'if (ci->ep != NULL)'), but we cannot assume the
 | 
				
			||||||
 | 
						 * caller has actually set up an osmo_fsm_set_dealloc_ctx(). At time of writing, e.g. osmo-hnbgw does not use
 | 
				
			||||||
 | 
						 * it.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * In osmo_mgcpc_ep_fsm_check_state_chg_after_response(), we do get an rc: false means FSM has terminated.
 | 
				
			||||||
 | 
						 * On termination, the ep emits a term event to the FSM's parent.
 | 
				
			||||||
 | 
						 * That may cause the notify.fi to be terminated in turn, depending on how the caller set things up.
 | 
				
			||||||
 | 
						 * So: we cannot store notify.fi before, then call osmo_mgcpc_ep_fsm_check_state_chg_after_response(), and then
 | 
				
			||||||
 | 
						 * emit the event, because notify.fi may have deallocated. We cannot look up whether
 | 
				
			||||||
 | 
						 * osmo_mgcpc_ep_cancel_notify() has been called, because ci may have deallocated along with ci->ep.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We have to skip emitting below success event in case the ep is now terminated.
 | 
				
			||||||
 | 
						 * - It may be the final DLCX OK: not a problem, osmo_mgcpc_ep_ci_dlcx() has no notify args on purpose, so we do
 | 
				
			||||||
 | 
						 *   make all callers not set a notify event for DLCX by design. notify.fi should always be NULL when the final
 | 
				
			||||||
 | 
						 *   DLCX OK terminates the local endpoint state.
 | 
				
			||||||
 | 
						 * - It may also be sudden termination due to a bad problem, in which case we shouldn't emit success.
 | 
				
			||||||
 | 
						 *   The osmo_fsm_inst.parent_term_event should suffice as feedback to the caller.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi) == false) {
 | 
				
			||||||
 | 
							/* false means, the ci->ep has been terminated. */
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ci->notify.fi)
 | 
						if (ci->notify.fi)
 | 
				
			||||||
		osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
 | 
							osmo_fsm_inst_dispatch(ci->notify.fi, ci->notify.success, ci->notify.data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Return the MGW's 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 +583,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 +679,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) {
 | 
				
			||||||
@@ -644,11 +718,11 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			|||||||
	osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
 | 
						osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
 | 
				
			||||||
	*ci = cleared_ci;
 | 
						*ci = cleared_ci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (verb_info)
 | 
						if (verb_info)
 | 
				
			||||||
		ci->verb_info = *verb_info;
 | 
							ci->verb_info = *verb_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify.fi));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ep->endpoint[0]) {
 | 
						if (ep->endpoint[0]) {
 | 
				
			||||||
		if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
 | 
							if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
 | 
				
			||||||
			LOG_CI(ci, LOGL_ERROR,
 | 
								LOG_CI(ci, LOGL_ERROR,
 | 
				
			||||||
@@ -979,6 +1053,34 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static 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 +1088,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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_fsm.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
#include <osmocom/core/fsm.h>
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
@@ -114,12 +115,10 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
 | 
				
			|||||||
		.call_id = info->call_id,
 | 
							.call_id = info->call_id,
 | 
				
			||||||
		.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
							.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
				
			||||||
		.ptime = info->ptime,
 | 
							.ptime = info->ptime,
 | 
				
			||||||
		.codecs_len = info->codecs_len,
 | 
					 | 
				
			||||||
		.ptmap_len = info->ptmap_len,
 | 
							.ptmap_len = info->ptmap_len,
 | 
				
			||||||
		.param_present = info->param_present
 | 
							.param_present = info->param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
 | 
					 | 
				
			||||||
	memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
						memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
				
			||||||
	memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
 | 
						memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,10 +135,19 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
					static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT;
 | 
						bool ip_is_set = info->addr[0] != '\0' &&
 | 
				
			||||||
	mgcp_msg->audio_ip = info->addr;
 | 
								 strncmp(info->addr, "::", sizeof(info->addr)) != 0 &&
 | 
				
			||||||
	mgcp_msg->audio_port = info->port;
 | 
								 strncmp(info->addr, "0.0.0.0", sizeof(info->addr)) != 0;
 | 
				
			||||||
	mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
						if (ip_is_set) {
 | 
				
			||||||
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_IP;
 | 
				
			||||||
 | 
							mgcp_msg->audio_ip = info->addr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (info->port) {
 | 
				
			||||||
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_AUDIO_PORT;
 | 
				
			||||||
 | 
							mgcp_msg->audio_port = info->port;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ip_is_set && info->port)
 | 
				
			||||||
 | 
							mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
 | 
					static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
 | 
				
			||||||
@@ -149,6 +157,7 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer
 | 
				
			|||||||
		mgcp_msg->conn_mode = conn_mode;
 | 
							mgcp_msg->conn_mode = conn_mode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* returns message buffer containing MGXP MDCX on success, NULL on error. */
 | 
				
			||||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
					static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_msg mgcp_msg;
 | 
						struct mgcp_msg mgcp_msg;
 | 
				
			||||||
@@ -163,12 +172,10 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			|||||||
		.audio_ip = mgcp_ctx->conn_peer_local.addr,
 | 
							.audio_ip = mgcp_ctx->conn_peer_local.addr,
 | 
				
			||||||
		.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
							.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
				
			||||||
		.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
							.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
				
			||||||
		.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
 | 
					 | 
				
			||||||
		.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
 | 
							.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
 | 
				
			||||||
		.param_present = mgcp_ctx->conn_peer_local.param_present
 | 
							.param_present = mgcp_ctx->conn_peer_local.param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
 | 
					 | 
				
			||||||
	memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
						memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
				
			||||||
	memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
 | 
						memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,6 +193,7 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			|||||||
	return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
						return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* returns message buffer containing MGXP DLCX on success, NULL on error. */
 | 
				
			||||||
struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
					struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_msg mgcp_msg;
 | 
						struct mgcp_msg mgcp_msg;
 | 
				
			||||||
@@ -221,13 +229,14 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			|||||||
			 mgcp_ctx->conn_peer_local.endpoint);
 | 
								 mgcp_ctx->conn_peer_local.endpoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
							make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
		if (mgcp_ctx->conn_peer_local.port)
 | 
							add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
			add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
					 | 
				
			||||||
		set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
							set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
							msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
 | 
							mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg);
 | 
				
			||||||
		mgcp_ctx->mgw_trans_pending = true;
 | 
							mgcp_ctx->mgw_trans_pending = true;
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi);
 | 
				
			||||||
@@ -252,6 +261,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;
 | 
				
			||||||
@@ -352,13 +373,21 @@ static void fsm_ready_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			|||||||
	switch (event) {
 | 
						switch (event) {
 | 
				
			||||||
	case EV_MDCX:
 | 
						case EV_MDCX:
 | 
				
			||||||
		msg = make_mdcx_msg(mgcp_ctx);
 | 
							msg = make_mdcx_msg(mgcp_ctx);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								/* make_mdcx_msg() should already have logged the error */
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_mdcx_resp_cb, fi);
 | 
				
			||||||
		new_state = ST_MDCX_RESP;
 | 
							new_state = ST_MDCX_RESP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case EV_DLCX:
 | 
						case EV_DLCX:
 | 
				
			||||||
		msg = make_dlcx_msg(mgcp_ctx);
 | 
							msg = make_dlcx_msg(mgcp_ctx);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							if (!msg) {
 | 
				
			||||||
 | 
								/* make_dlcx_msg() should already have logged the error */
 | 
				
			||||||
 | 
								osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
 | 
							rc = mgcp_client_tx(mgcp, msg, mgw_dlcx_resp_cb, fi);
 | 
				
			||||||
		new_state = ST_DLCX_RESP;
 | 
							new_state = ST_DLCX_RESP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -521,10 +550,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,8 +625,75 @@ 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,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Provide backwards compat for deprecated conn_peer->codecs[]: when the caller passes in an mgcp_conn_peer instance
 | 
				
			||||||
 | 
					 * that has codecs[] set, apply it to ptmap[] instead. */
 | 
				
			||||||
 | 
					static void mgcp_conn_peer_compat(struct mgcp_conn_peer *conn_peer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!conn_peer->codecs_len)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Before dropping codecs[], codecs[] would indicate the order in which the codecs should appear in SDP. ptmap[]
 | 
				
			||||||
 | 
						 * would indicate payload type numbers when not using a default payload type number (may omit entries).
 | 
				
			||||||
 | 
						 * Now, ptmap[] just indicates both at the same time; codecs[] should be empty, and ptmap[] lists all codecs.
 | 
				
			||||||
 | 
						 * So if any codecs[] are present, recreate ptmap[] in the order of codecs[]. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptmap_len = 0;
 | 
				
			||||||
 | 
						for (int i = 0; i < conn_peer->codecs_len; i++) {
 | 
				
			||||||
 | 
							enum mgcp_codecs codec = conn_peer->codecs[i];
 | 
				
			||||||
 | 
							struct ptmap *found = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Look up whether a specific pt was indicated for this codec */
 | 
				
			||||||
 | 
							for (int p = 0; p < conn_peer->ptmap_len; p++) {
 | 
				
			||||||
 | 
								if (conn_peer->ptmap[p].codec != codec)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								found = &conn_peer->ptmap[p];
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (found) {
 | 
				
			||||||
 | 
								ptmap[ptmap_len] = *found;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ptmap[ptmap_len] = (struct ptmap){
 | 
				
			||||||
 | 
									.codec = codec,
 | 
				
			||||||
 | 
									/* some enum mgcp_codecs correspond to their standard PT nr, so for compat: */
 | 
				
			||||||
 | 
									.pt = codec,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ptmap_len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Are there any entries in the old ptmap that were omitted by codecs[]? */
 | 
				
			||||||
 | 
						for (int p = 0; p < conn_peer->ptmap_len; p++) {
 | 
				
			||||||
 | 
							bool exists = false;
 | 
				
			||||||
 | 
							for (int i = 0; i < ptmap_len; i++) {
 | 
				
			||||||
 | 
								if (ptmap_cmp(&ptmap[i], &conn_peer->ptmap[p]))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								exists = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (exists)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ptmap_len >= ARRAY_SIZE(ptmap))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Not present yet, add it to the end */
 | 
				
			||||||
 | 
							ptmap[ptmap_len] = conn_peer->ptmap[p];
 | 
				
			||||||
 | 
							ptmap_len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use the new ptmap[], and clear out legacy codecs[]. */
 | 
				
			||||||
 | 
						memcpy(conn_peer->ptmap, ptmap, sizeof(conn_peer->ptmap));
 | 
				
			||||||
 | 
						conn_peer->ptmap_len = ptmap_len;
 | 
				
			||||||
 | 
						conn_peer->codecs_len = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate FSM, and create a new connection on the MGW.
 | 
					/*! allocate FSM, and create a new connection on the MGW.
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \param[in] parent_fi Parent FSM instance.
 | 
					 *  \param[in] parent_fi Parent FSM instance.
 | 
				
			||||||
@@ -610,6 +708,7 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
 | 
				
			|||||||
	struct osmo_fsm_inst *fi;
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
	struct in6_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_peer_compat(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(parent_fi);
 | 
						OSMO_ASSERT(parent_fi);
 | 
				
			||||||
	OSMO_ASSERT(mgcp);
 | 
						OSMO_ASSERT(mgcp);
 | 
				
			||||||
@@ -649,6 +748,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
	struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
						struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
				
			||||||
	struct in6_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_peer_compat(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(mgcp_ctx);
 | 
						OSMO_ASSERT(mgcp_ctx);
 | 
				
			||||||
	OSMO_ASSERT(conn_peer);
 | 
						OSMO_ASSERT(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -707,8 +808,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
 | 
				
			||||||
@@ -745,7 +846,7 @@ const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			|||||||
	return buf;
 | 
						return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
 | 
					static __attribute__((constructor)) void osmo_mgcp_client_fsm_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										298
									
								
								src/libosmo-mgcp-client/mgcp_client_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								src/libosmo-mgcp-client/mgcp_client_pool.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,298 @@
 | 
				
			|||||||
 | 
					/* (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 <asm-generic/errno.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>
 | 
				
			||||||
 | 
					#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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! 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->member_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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->member_list, list) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Initialize client */
 | 
				
			||||||
 | 
							if (mgcp_client_pool_member_reinit_client(pool_member) == 0)
 | 
				
			||||||
 | 
								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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool mgcp_client_pool_empty(const struct mgcp_client_pool *pool)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return llist_empty(&pool->member_list);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Lookup the selected MGCP client config by its reference number */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							if (pool_member->nr == nr)
 | 
				
			||||||
 | 
								return pool_member;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
				
			||||||
 | 
					 * pool member that is suitable (is not blocked, has a client with a working link, has a low load). */
 | 
				
			||||||
 | 
					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 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							n_pool_members++;
 | 
				
			||||||
 | 
							bool conn_up = pool_member->client && pool_member->client->conn_up;
 | 
				
			||||||
 | 
							if (pool_member->blocked == false && conn_up) {
 | 
				
			||||||
 | 
								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, "%s -- MGW %u is unusable (blocked=%u, cli=%u, link=%u)\n",
 | 
				
			||||||
 | 
									 __func__, pool_member->nr, pool_member->blocked, !!pool_member->client, conn_up);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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->member_list) && 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->member_list)) {
 | 
				
			||||||
 | 
							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)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mgcp_client_pool_member_get(pool_member);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_client)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_client->pool_member)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						pool_member = mgcp_client->pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pool_member->refcount == 0) {
 | 
				
			||||||
 | 
							LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pool_member->refcount--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***************************
 | 
				
			||||||
 | 
					 * mgcp_client_pool_member:
 | 
				
			||||||
 | 
					 ***************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Allocate an mgcp_client_pool_member.
 | 
				
			||||||
 | 
					 *  \param[in] pool MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] nr Reference number of the pool member.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = talloc_zero(pool, struct mgcp_client_pool_member);
 | 
				
			||||||
 | 
						OSMO_ASSERT(pool_member);
 | 
				
			||||||
 | 
						mgcp_client_conf_init(&pool_member->conf);
 | 
				
			||||||
 | 
						pool_member->pool = pool;
 | 
				
			||||||
 | 
						pool_member->nr = nr;
 | 
				
			||||||
 | 
						llist_add_tail(&pool_member->list, &pool->member_list);
 | 
				
			||||||
 | 
						return pool_member;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Free an mgcp_client_pool_member allocated through mgcp_client_pool_member_alloc().
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It also frees the associated MGCP client if present.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_del(&pool_member->list);
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						talloc_free(pool_member);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Recreate and reconnect the MGCP client associated to the pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* 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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
				
			||||||
 | 
						pool_member->client->pool_member = pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Connect client */
 | 
				
			||||||
 | 
						if (mgcp_client_connect(pool_member->client)) {
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
							return -ECONNABORTED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get the MGCP client associated with the pool reference from the pool (increment reference counter).
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns MGCP client descriptor, NULL if no member was not ready.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pool_member->refcount++;
 | 
				
			||||||
 | 
						return pool_member->client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get whether the MGCP client associated with the pool reference is blocked by policy.
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns true if blocked, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return pool_member->blocked;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
/* MGCP client interface to quagga VTY */
 | 
					/* MGCP client interface to quagga VTY */
 | 
				
			||||||
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
 | 
					/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
					 * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
 | 
				
			||||||
 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
 | 
					 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * (C) 2009-2011 by Holger Hans Peter Freyther
 | 
					 * (C) 2009-2011 by Holger Hans Peter Freyther
 | 
				
			||||||
@@ -24,28 +24,78 @@
 | 
				
			|||||||
#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/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool.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 commands 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Global single MGCP config, deprecated: */
 | 
				
			||||||
 | 
						vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
				
			||||||
 | 
							"You should consider reading the User Manual and migrating to 'mgw' node.%s",
 | 
				
			||||||
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return global_mgcp_client_conf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct mgcp_client *get_mgcp_client(struct vty *vty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node) {
 | 
				
			||||||
 | 
							llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
				
			||||||
 | 
								/* Find matching the conf pointer: */
 | 
				
			||||||
 | 
								if (&pool_member->conf != conf)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								return pool_member->client;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Global single MGCP config, deprecated: */
 | 
				
			||||||
 | 
						vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
				
			||||||
 | 
							"You should consider reading the User Manual and migrating to 'mgw' node.%s",
 | 
				
			||||||
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* There's no way to obtain the struct mgcp_client in old interface, but anyway it's deprecated. */
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "mgw local-ip " VTY_IPV46_CMD,
 | 
					      "local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "local bind to connect to MGW from\n"
 | 
					      "local bind to connect to MGW from\n"
 | 
				
			||||||
      "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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -53,57 +103,77 @@ ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
 | 
				
			|||||||
		 "mgcpgw local-ip A.B.C.D",
 | 
							 "mgcpgw local-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind IP address\n")
 | 
							 "local bind IP address\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_local_ip,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_local_ip_cmd,
 | 
				
			||||||
 | 
							 "mgw local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
 | 
							 MGW_STR "local bind to connect to MGW from\n"
 | 
				
			||||||
 | 
							 "local bind IPv4 address\n"
 | 
				
			||||||
 | 
							 "local bind IPv6 address\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
					DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
				
			||||||
      "mgw local-port <0-65535>",
 | 
					      "local-port <0-65535>",
 | 
				
			||||||
      MGW_STR "local port to connect to MGW from\n"
 | 
					      "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,
 | 
				
			||||||
		 "mgcpgw local-port <0-65535>",
 | 
							 "mgcpgw local-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind port\n")
 | 
							 "local bind port\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_local_port,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_local_port_cmd,
 | 
				
			||||||
 | 
							 "mgw local-port <0-65535>",
 | 
				
			||||||
 | 
							 MGW_STR "local port to connect to MGW from\n"
 | 
				
			||||||
 | 
							 "local bind port\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
					DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
				
			||||||
      "mgw remote-ip " VTY_IPV46_CMD,
 | 
					      "remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "remote IP address to reach the MGW at\n"
 | 
					      "remote IP address to reach the MGW at\n"
 | 
				
			||||||
      "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,
 | 
				
			||||||
		 "mgcpgw remote-ip A.B.C.D",
 | 
							 "mgcpgw remote-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind IP address\n")
 | 
							 "remote bind IP address\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_ip,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_remote_ip_cmd,
 | 
				
			||||||
 | 
							 "mgw remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
 | 
							 MGW_STR "remote IP address to reach the MGW at\n"
 | 
				
			||||||
 | 
							 "remote IPv4 address\n"
 | 
				
			||||||
 | 
							 "remote IPv6 address\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
					DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
				
			||||||
      "mgw remote-port <0-65535>",
 | 
					      "remote-port <0-65535>",
 | 
				
			||||||
      MGW_STR "remote port to reach the MGW at\n"
 | 
					      "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,
 | 
				
			||||||
		 "mgcpgw remote-port <0-65535>",
 | 
							 "mgcpgw remote-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind port\n")
 | 
							 "remote bind port\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_port,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_remote_port_cmd,
 | 
				
			||||||
 | 
							 "mgw remote-port <0-65535>",
 | 
				
			||||||
 | 
							 MGW_STR "remote port to reach the MGW at\n"
 | 
				
			||||||
 | 
							 "remote port\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
 | 
					DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
					      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
				
			||||||
      "-\n" "-\n")
 | 
					      "-\n" "-\n")
 | 
				
			||||||
@@ -113,7 +183,7 @@ DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
 | 
				
			|||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "usable range of endpoint identifiers\n"
 | 
					      MGW_STR "usable range of endpoint identifiers\n"
 | 
				
			||||||
      "set first useable endpoint identifier\n"
 | 
					      "set first useable endpoint identifier\n"
 | 
				
			||||||
@@ -141,62 +211,278 @@ ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_endpoint_domain_name,
 | 
					DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			||||||
      cfg_mgw_endpoint_domain_name_cmd,
 | 
					      cfg_mgw_endpoint_domain_name_cmd,
 | 
				
			||||||
      "mgw endpoint-domain NAME",
 | 
					      "endpoint-domain NAME",
 | 
				
			||||||
      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
					      "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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_endpoint_domain_name,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_endpoint_domain_name_cmd,
 | 
				
			||||||
 | 
					      "mgw endpoint-domain NAME",
 | 
				
			||||||
 | 
					      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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
					DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "reset-endpoint NAME",
 | 
				
			||||||
 | 
					      "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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_no_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "no reset-endpoint NAME",
 | 
				
			||||||
 | 
					      NO_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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgw_mgw_keepalive_req_interval,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_keepalive_req_interval_cmd,
 | 
				
			||||||
 | 
					      "keepalive request-interval <0-4294967295>",
 | 
				
			||||||
 | 
					      "Monitor if the MGCP link against MGW is still usable\n"
 | 
				
			||||||
 | 
					      "Send an MGCP command to the MGW at given interval if no other commands are sent\n"
 | 
				
			||||||
 | 
					      "The interval at which send MGCP commands (s), 0 to disable\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conf->keepalive.req_interval_sec = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If client already exists, apply the change immediately if possible: */
 | 
				
			||||||
 | 
						mgcp->actual.keepalive.req_interval_sec = atoi(argv[0]);
 | 
				
			||||||
 | 
						if (mgcp->iofd) { /* UDP MGCP socket connected */
 | 
				
			||||||
 | 
							if (mgcp->actual.keepalive.req_interval_sec > 0) {
 | 
				
			||||||
 | 
								/* Re-schedule: */
 | 
				
			||||||
 | 
								osmo_timer_schedule(&mgcp->keepalive_tx_timer, mgcp->actual.keepalive.req_interval_sec, 0);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (osmo_timer_pending(&mgcp->keepalive_tx_timer))
 | 
				
			||||||
 | 
									osmo_timer_del(&mgcp->keepalive_tx_timer);
 | 
				
			||||||
 | 
								/* Assume link is UP by default, so that this MGW can be selected: */
 | 
				
			||||||
 | 
								mgcp->conn_up = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} /* else: wait until connect() to do first scheduling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
 | 
					DEFUN(cfg_mgw_mgw_keepalive_req_endpoint,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_keepalive_req_endpoint_cmd,
 | 
				
			||||||
 | 
					      "keepalive request-endpoint NAME",
 | 
				
			||||||
 | 
					      "Monitor if the MGCP link against MGW is still usable\n"
 | 
				
			||||||
 | 
					      "Use a given endpoint name when sending an MGCP command to the MGW for keepalive purposes\n"
 | 
				
			||||||
 | 
					      "The name of the endpoint to use\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_STRLCPY_ARRAY(conf->keepalive.req_endpoint_name, argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If client already exists, apply the change immediately if possible: */
 | 
				
			||||||
 | 
						OSMO_STRLCPY_ARRAY(mgcp->actual.keepalive.req_endpoint_name, argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgw_mgw_keepalive_timeout,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_keepalive_timeout_cmd,
 | 
				
			||||||
 | 
					      "keepalive timeout <0-4294967295>",
 | 
				
			||||||
 | 
					      "Monitor if the MGCP link against MGW is still usable\n"
 | 
				
			||||||
 | 
					      "Consider the link to the MGW to be down after time without receiving any message from it\n"
 | 
				
			||||||
 | 
					      "The timeout (s), 0 to disable\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp = get_mgcp_client(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conf->keepalive.timeout_sec = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If client already exists, apply the change immediately if possible: */
 | 
				
			||||||
 | 
						mgcp->actual.keepalive.timeout_sec = atoi(argv[0]);
 | 
				
			||||||
 | 
						if (mgcp->iofd) { /* UDP MGCP socket connected */
 | 
				
			||||||
 | 
							if (mgcp->actual.keepalive.timeout_sec > 0) {
 | 
				
			||||||
 | 
								/* Re-schedule: */
 | 
				
			||||||
 | 
								osmo_timer_schedule(&mgcp->keepalive_rx_timer, mgcp->actual.keepalive.timeout_sec, 0);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (osmo_timer_pending(&mgcp->keepalive_rx_timer))
 | 
				
			||||||
 | 
									osmo_timer_del(&mgcp->keepalive_rx_timer);
 | 
				
			||||||
 | 
								/* Assume link is UP by default, so that this MGW can be selected: */
 | 
				
			||||||
 | 
								mgcp->conn_up = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} /* else: wait until connect() to do first scheduling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *addr;
 | 
				
			||||||
 | 
						int port;
 | 
				
			||||||
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If caller doesn't the MGW pool API (mgcp_client_pool_vty_init was never called),
 | 
				
			||||||
 | 
						 * then the "mgw" cmd prefix must be added since the old node always contained it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const char *mgw_prefix = global_mgcp_client_pool ? "" : "mgw ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->description) /* description never had "mgw" prefix even on old node: */
 | 
				
			||||||
 | 
							vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = conf->local_addr;
 | 
				
			||||||
 | 
						if (addr)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%slocal-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
				
			||||||
 | 
						port = conf->local_port;
 | 
				
			||||||
 | 
						if (port >= 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%slocal-port %u%s", indent, mgw_prefix,
 | 
				
			||||||
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = conf->remote_addr;
 | 
				
			||||||
 | 
						if (addr)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%sremote-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
				
			||||||
 | 
						port = conf->remote_port;
 | 
				
			||||||
 | 
						if (port >= 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%sremote-port %u%s", indent, mgw_prefix,
 | 
				
			||||||
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->endpoint_domain_name[0])
 | 
				
			||||||
 | 
							vty_out(vty, "%s%sendpoint-domain %s%s", indent, mgw_prefix,
 | 
				
			||||||
 | 
								conf->endpoint_domain_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->keepalive.req_interval_sec != 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%skeepalive request-interval %u%s", indent, mgw_prefix,
 | 
				
			||||||
 | 
								conf->keepalive.req_interval_sec, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (strncmp(conf->keepalive.req_endpoint_name, MGCP_CLIENT_KEEPALIVE_DEFAULT_ENDP,
 | 
				
			||||||
 | 
							    sizeof(conf->keepalive.req_endpoint_name)) != 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%skeepalive request-endpoint %s%s", indent,  mgw_prefix,
 | 
				
			||||||
 | 
								conf->keepalive.req_endpoint_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (conf->keepalive.timeout_sec != 0)
 | 
				
			||||||
 | 
							vty_out(vty, "%s%skeepalive timeout %u%s", indent,  mgw_prefix,
 | 
				
			||||||
 | 
								conf->keepalive.timeout_sec, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* If caller supports MGW pool API (mgcp_client_pool_vty_init was
 | 
				
			||||||
 | 
						 * called), then skip printing any config in this node and print it when
 | 
				
			||||||
 | 
						 * the whole 'mgw' node is printed. */
 | 
				
			||||||
 | 
						if (global_mgcp_client_pool)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
						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);
 | 
						/* deprecated 'mgw' commands ('mgw' prepended as first arg) */
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_local_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_remote_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_local_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_remote_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_remote_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_remote_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_endpoint_range_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_mgw_keepalive_req_interval_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_mgw_keepalive_req_endpoint_cmd);
 | 
				
			||||||
 | 
						install_lib_element(node, &cfg_mgw_mgw_keepalive_timeout_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! 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 +492,254 @@ 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Mark whether user called mgcp_client_pool_config_write() and hence support new API */
 | 
				
			||||||
 | 
					static bool mgcp_client_pool_config_write_called = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						unsigned int subindent_buf_len;
 | 
				
			||||||
 | 
						char *subindent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!indent)
 | 
				
			||||||
 | 
							indent = pool->vty_indent ? : "";
 | 
				
			||||||
 | 
						subindent_buf_len = strlen(indent) + 1 + 1;
 | 
				
			||||||
 | 
						subindent = talloc_zero_size(vty, subindent_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(subindent, subindent_buf_len, "%s ", indent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw %u%s", indent, pool_member->nr, VTY_NEWLINE);
 | 
				
			||||||
 | 
							config_write(vty, subindent, &pool_member->conf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* MGW pool API is supported by user (global_mgcp_client_pool is set
 | 
				
			||||||
 | 
						 * because mgcp_client_pool_vty_init was called). If single MGW was
 | 
				
			||||||
 | 
						 * configured through old VTY and no mgw in the new MGW pool VTY is
 | 
				
			||||||
 | 
						 * replacing it, then output the single MGW converted to the new MGW
 | 
				
			||||||
 | 
						 * pool VTY. */
 | 
				
			||||||
 | 
						if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw 0%s", indent, VTY_NEWLINE);
 | 
				
			||||||
 | 
							config_write(vty, subindent, global_mgcp_client_conf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(subindent);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Deprecated, used for backward compatibility with older users which didn't call
 | 
				
			||||||
 | 
					 * mgcp_client_pool_config_write(): */
 | 
				
			||||||
 | 
					static int config_write_pool(struct vty *vty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (mgcp_client_pool_config_write_called)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return _mgcp_client_pool_config_write(vty, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Write out MGCP client config to VTY.
 | 
				
			||||||
 | 
					 *  \param[in] vty VTY to which we should print.
 | 
				
			||||||
 | 
					 *  \param[in] indent string used for indentation (e.g. " ").
 | 
				
			||||||
 | 
						       If NULL, indentation passed during mgcp_client_pool_vty_init() will be used.
 | 
				
			||||||
 | 
					 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
				
			||||||
 | 
					int mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Tell internal node write function that the user supports calling proper API: */
 | 
				
			||||||
 | 
						mgcp_client_pool_config_write_called = true;
 | 
				
			||||||
 | 
						return _mgcp_client_pool_config_write(vty, indent);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
 | 
						if (!pool_member) {
 | 
				
			||||||
 | 
							pool_member = mgcp_client_pool_member_alloc(global_mgcp_client_pool, nr);
 | 
				
			||||||
 | 
							OSMO_ASSERT(pool_member);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_client_pool_member_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 = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_client_pool_member_reinit_client(pool_member) < 0) {
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
							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 = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, 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 = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, 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_show_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->member_list) && 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->member_list)) {
 | 
				
			||||||
 | 
							vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
				
			||||||
 | 
							const struct mgcp_client *cli = pool_member->client;
 | 
				
			||||||
 | 
							vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "%%   MGCP link:     %s,%s%s",
 | 
				
			||||||
 | 
								cli && cli->iofd ? "connected" : "disconnected",
 | 
				
			||||||
 | 
								cli && cli->conn_up ?
 | 
				
			||||||
 | 
									((cli->actual.keepalive.timeout_sec > 0) ? "UP" : "MAYBE") :
 | 
				
			||||||
 | 
									"DOWN",
 | 
				
			||||||
 | 
								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.
 | 
				
			||||||
 | 
						       If NULL, it must be passed explicitly each time mgcp_client_pool_config_write() is called.
 | 
				
			||||||
 | 
					 *  \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_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (indent) {
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note: config_write_pool is deprecated and user is expected to
 | 
				
			||||||
 | 
						 * manually call mgcp_client_pool_config_write() when printing the VTY
 | 
				
			||||||
 | 
						 * config */
 | 
				
			||||||
 | 
						install_node(pool->vty_node, config_write_pool);
 | 
				
			||||||
 | 
						vty_init_common(pool, mgw_node);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_local_ip_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_local_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_remote_ip_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_remote_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_reset_ep_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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_show_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						global_mgcp_client_pool = pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,6 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOGSM_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOVTY_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMONETIF_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOABIS_LIBS) \
 | 
					 | 
				
			||||||
	$(LIBOSMOTRAU_LIBS) \
 | 
					 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +39,8 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_stat.c \
 | 
						mgcp_stat.c \
 | 
				
			||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
	mgcp_trunk.c \
 | 
						mgcp_trunk.c \
 | 
				
			||||||
	mgcp_ctrl.c \
 | 
					 | 
				
			||||||
	mgcp_ratectr.c \
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
 | 
						mgcp_rtp_end.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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Helper function to dump codec information of a specified codec to a printable
 | 
					/* Helper function to dump codec information of a specified codec to a printable
 | 
				
			||||||
 * string, used by dump_codec_summary() */
 | 
					 * string, used by dump_codec_summary() */
 | 
				
			||||||
static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
					static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char str[256];
 | 
						static char str[256];
 | 
				
			||||||
	char *pt_str;
 | 
						char *pt_str;
 | 
				
			||||||
@@ -49,31 +49,25 @@ static char *dump_codec(struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dump a summary of all negotiated codecs to debug log
 | 
					/*! Dump a summary of all negotiated codecs to debug log
 | 
				
			||||||
 *  \param[in] conn related rtp-connection. */
 | 
					 *  \param[in] cset related codecset.
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
					 *  \param[in] prefix_str Prefix string to print during logging.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
 | 
					void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp = &conn->end;
 | 
						if (cset->codecs_assigned == 0) {
 | 
				
			||||||
	endp = conn->conn->endp;
 | 
							LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rtp->codecs_assigned == 0) {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
 | 
					 | 
				
			||||||
			 mgcp_conn_dump(conn->conn));
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Store parsed codec information */
 | 
						/* Store parsed codec information */
 | 
				
			||||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
		codec = &rtp->codecs[i];
 | 
							struct mgcp_rtp_codec *codec = &cset->codecs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec));
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn), i, dump_codec(codec));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (codec == rtp->codec)
 | 
							if (codec == cset->codec)
 | 
				
			||||||
			LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
 | 
								LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_DEBUG, "\n");
 | 
							LOGPC(DLMGCP, LOGL_DEBUG, "\n");
 | 
				
			||||||
@@ -81,7 +75,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initalize or reset codec information with default data. */
 | 
					/* Initalize or reset codec information with default data. */
 | 
				
			||||||
static void codec_init(struct mgcp_rtp_codec *codec)
 | 
					static void mgcp_codec_init(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	*codec = (struct mgcp_rtp_codec){
 | 
						*codec = (struct mgcp_rtp_codec){
 | 
				
			||||||
		.payload_type = -1,
 | 
							.payload_type = -1,
 | 
				
			||||||
@@ -89,27 +83,25 @@ 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 mgcp_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){};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initalize or reset codec information with default data.
 | 
					/*! Initalize or reset codec information with default data.
 | 
				
			||||||
 *  \param[out] conn related rtp-connection. */
 | 
					 *  \param[out] conn related rtp-connection. */
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
					void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < conn->end.codecs_assigned; i++)
 | 
						for (i = 0; i < cset->codecs_assigned; i++)
 | 
				
			||||||
		codec_free(&conn->end.codecs[i]);
 | 
							mgcp_codec_free(&cset->codecs[i]);
 | 
				
			||||||
	conn->end.codecs_assigned = 0;
 | 
						cset->codecs_assigned = 0;
 | 
				
			||||||
	conn->end.codec = NULL;
 | 
						cset->codec = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Add codec configuration depending on payload type and/or codec name. This
 | 
					/*! Add codec configuration depending on payload type and/or codec name. This
 | 
				
			||||||
@@ -120,25 +112,23 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
					 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
				
			||||||
 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
					 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
					int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rate;
 | 
						int rate;
 | 
				
			||||||
	int channels;
 | 
						int channels;
 | 
				
			||||||
	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 = cset->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. */
 | 
				
			||||||
	if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
 | 
						if (cset->codecs_assigned >= MGCP_MAX_CODECS)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* First unused entry */
 | 
						/* First unused entry */
 | 
				
			||||||
	codec = &conn->end.codecs[conn->end.codecs_assigned];
 | 
						codec = &cset->codecs[cset->codecs_assigned];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Initalize the codec struct with some default data to begin with */
 | 
						/* Initalize the codec struct with some default data to begin with */
 | 
				
			||||||
	codec_init(codec);
 | 
						mgcp_codec_init(codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (payload_type != PTYPE_UNDEFINED) {
 | 
						if (payload_type != PTYPE_UNDEFINED) {
 | 
				
			||||||
		/* Make sure we do not get any reserved or undefined type numbers */
 | 
							/* Make sure we do not get any reserved or undefined type numbers */
 | 
				
			||||||
@@ -160,16 +150,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 +169,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 {
 | 
				
			||||||
@@ -272,80 +262,11 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
 | 
				
			|||||||
	} else
 | 
						} else
 | 
				
			||||||
		codec->param_present = false;
 | 
							codec->param_present = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->end.codecs_assigned++;
 | 
						cset->codecs_assigned++;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	/* Make sure we leave a clean codec entry on error. */
 | 
						/* Make sure we leave a clean codec entry on error. */
 | 
				
			||||||
	codec_free(codec);
 | 
						mgcp_codec_free(codec);
 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if the given codec is applicable on the specified endpoint
 | 
					 | 
				
			||||||
 * Helper function for mgcp_codec_decide() */
 | 
					 | 
				
			||||||
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* A codec name must be set, if not, this might mean that the codec
 | 
					 | 
				
			||||||
	 * (payload type) that was assigned is unknown to us so we must stop
 | 
					 | 
				
			||||||
	 * here. */
 | 
					 | 
				
			||||||
	if (!codec->subtype_name)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: implement meaningful checks to make sure that the given codec
 | 
					 | 
				
			||||||
	 * is compatible with the given endpoint */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Decide for one suitable codec
 | 
					 | 
				
			||||||
 *  \param[in] conn related rtp-connection.
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	bool codec_assigned = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endp = conn->conn->endp;
 | 
					 | 
				
			||||||
	rtp = &conn->end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* This function works on the results the SDP/LCO parser has extracted
 | 
					 | 
				
			||||||
	 * from the MGCP message. The goal is to select a suitable codec for
 | 
					 | 
				
			||||||
	 * the given connection. When transcoding is available, the first codec
 | 
					 | 
				
			||||||
	 * from the codec list is taken without further checking. When
 | 
					 | 
				
			||||||
	 * transcoding is not available, then the choice must be made more
 | 
					 | 
				
			||||||
	 * carefully. Each codec in the list is checked until one is found that
 | 
					 | 
				
			||||||
	 * is rated compatible. The rating is done by the helper function
 | 
					 | 
				
			||||||
	 * is_codec_compatible(), which does the actual checking. */
 | 
					 | 
				
			||||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
					 | 
				
			||||||
		/* When no transcoding is available, avoid codecs that would
 | 
					 | 
				
			||||||
		 * require transcoding. */
 | 
					 | 
				
			||||||
		if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
 | 
					 | 
				
			||||||
			     rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rtp->codec = &rtp->codecs[i];
 | 
					 | 
				
			||||||
		codec_assigned = true;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: To the reviewes: This is problematic. I do not get why we
 | 
					 | 
				
			||||||
	 * need to reset the packet_duration_ms depending on the codec
 | 
					 | 
				
			||||||
	 * selection. I thought it were all 20ms? Is this to address some
 | 
					 | 
				
			||||||
	 * cornercase. (This piece of code was in the code path before,
 | 
					 | 
				
			||||||
	 * together with the note: "TODO/XXX: Store this per codec and derive
 | 
					 | 
				
			||||||
	 * it on use" */
 | 
					 | 
				
			||||||
	if (codec_assigned) {
 | 
					 | 
				
			||||||
		if (rtp->maximum_packet_time >= 0
 | 
					 | 
				
			||||||
		    && rtp->maximum_packet_time * rtp->codec->frame_duration_den >
 | 
					 | 
				
			||||||
		    rtp->codec->frame_duration_num * 1500)
 | 
					 | 
				
			||||||
			rtp->packet_duration_ms = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -359,7 +280,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;
 | 
				
			||||||
@@ -368,10 +289,15 @@ static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
	return codec->param.amr_octet_aligned;
 | 
						return codec->param.amr_octet_aligned;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare two codecs, all parameters must match up, except for the payload type
 | 
					/* Compare two codecs, all parameters must match up */
 | 
				
			||||||
 * number. */
 | 
					static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers
 | 
				
			||||||
 | 
						 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal
 | 
				
			||||||
 | 
						 * payload type numbers. Also the audio_name is not checked since it is already parsed into subtype_name, rate,
 | 
				
			||||||
 | 
						 * and channels, which are checked. */
 | 
				
			||||||
 | 
						if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	if (codec_a->rate != codec_b->rate)
 | 
						if (codec_a->rate != codec_b->rate)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->channels != codec_b->channels)
 | 
						if (codec_a->channels != codec_b->channels)
 | 
				
			||||||
@@ -380,61 +306,167 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
						if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
					
 | 
				
			||||||
		return false;
 | 
						/* AMR payload may be formatted in two different payload formats, it is still the same codec but since the
 | 
				
			||||||
	if (!strcmp(codec_a->subtype_name, "AMR")) {
 | 
						 * formatting of the payload is different, conversation is required, so we must treat it as a different
 | 
				
			||||||
		if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
 | 
						 * codec here. */
 | 
				
			||||||
 | 
						if (strcmp(codec_a->subtype_name, "AMR") == 0) {
 | 
				
			||||||
 | 
							if (mgcp_codec_amr_is_octet_aligned(codec_a) != mgcp_codec_amr_is_octet_aligned(codec_b))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Translate a given payload type number that belongs to the packet of a
 | 
					/* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */
 | 
				
			||||||
 *  source connection to the equivalent payload type number that matches the
 | 
					static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
 *  configuration of a destination connection.
 | 
					{
 | 
				
			||||||
 *  \param[in] conn_src related source rtp-connection.
 | 
						/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to
 | 
				
			||||||
 *  \param[in] conn_dst related destination rtp-connection.
 | 
						 * translate between different payload formats as long as the encoded voice data itself does not change.
 | 
				
			||||||
 *  \param[in] payload_type number from the source packet or source connection.
 | 
						 * Therefore we must insist on equal codecs but still allow different payload formatting. */
 | 
				
			||||||
 *  \returns translated payload type number on success, -EINVAL on failure. */
 | 
					
 | 
				
			||||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type)
 | 
						/* In 3G IuUP, AMR may be encapsulated in IuFP, this means even though the codec name and negotiated rate is
 | 
				
			||||||
 | 
						 * different, the formatting can still be converted by OsmoMGW. Therefore we won't insist on equal
 | 
				
			||||||
 | 
						 * subtype_name and rate if we detect IuFP and AMR is used on the same tandem. */
 | 
				
			||||||
 | 
						if (strcmp(codec_a->subtype_name, "AMR") == 0 && strcmp(codec_b->subtype_name, "VND.3GPP.IUFP") == 0)
 | 
				
			||||||
 | 
							goto iufp;
 | 
				
			||||||
 | 
						if (strcmp(codec_a->subtype_name, "VND.3GPP.IUFP") == 0 && strcmp(codec_b->subtype_name, "AMR") == 0)
 | 
				
			||||||
 | 
							goto iufp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (codec_a->rate != codec_b->rate)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					iufp:
 | 
				
			||||||
 | 
						if (codec_a->channels != codec_b->channels)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (codec_a->frame_duration_num != codec_b->frame_duration_num)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *rtp_src;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end *rtp_dst;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec_src = NULL;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_codec *codec_dst = NULL;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	unsigned int codecs_assigned;
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_src = &conn_src->end;
 | 
						/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
				
			||||||
	rtp_dst = &conn_dst->end;
 | 
						 * the first run we will look for an exact match. */
 | 
				
			||||||
 | 
						codecs_assigned = cset->codecs_assigned;
 | 
				
			||||||
	/* Find the codec information that is used on the source side */
 | 
					 | 
				
			||||||
	codecs_assigned = rtp_src->codecs_assigned;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < codecs_assigned; i++) {
 | 
				
			||||||
		if (payload_type == rtp_src->codecs[i].payload_type) {
 | 
							if (codecs_same(codec, &cset->codecs[i])) {
 | 
				
			||||||
			codec_src = &rtp_src->codecs[i];
 | 
								return &cset->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!codec_src)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Use the codec infrmation from the source and try to find the
 | 
						return NULL;
 | 
				
			||||||
	 * equivalent of it on the destination side */
 | 
					}
 | 
				
			||||||
	codecs_assigned = rtp_dst->codecs_assigned;
 | 
					
 | 
				
			||||||
 | 
					/* For a given codec, find a convertible codec in the given connection. */
 | 
				
			||||||
 | 
					static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						unsigned int codecs_assigned;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec_convertible = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use the codec information from the source and try to find the equivalent of it on the destination side. In
 | 
				
			||||||
 | 
						 * the first run we will look for an exact match. */
 | 
				
			||||||
 | 
						codec_convertible = mgcp_codecset_find_same(cset, codec);
 | 
				
			||||||
 | 
						if (codec_convertible)
 | 
				
			||||||
 | 
							return codec_convertible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the
 | 
				
			||||||
 | 
						 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */
 | 
				
			||||||
 | 
						codecs_assigned = cset->codecs_assigned;
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < codecs_assigned; i++) {
 | 
				
			||||||
		if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
 | 
							if (codecs_convertible(codec, &cset->codecs[i])) {
 | 
				
			||||||
			codec_dst = &rtp_dst->codecs[i];
 | 
								codec_convertible = &cset->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!codec_dst)
 | 
					
 | 
				
			||||||
 | 
						return codec_convertible;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available,
 | 
				
			||||||
 | 
					 *  a tentative decision is made.
 | 
				
			||||||
 | 
					 *  \param[in] cset_src related codec set.
 | 
				
			||||||
 | 
					 *  \param[inout] cset_dst related destination codec set (NULL if not present).
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* In case no destination connection is available (yet), or in case the destination connection exists but has
 | 
				
			||||||
 | 
						 * no codecs assigned, we are forced to make a simple tentative decision:
 | 
				
			||||||
 | 
						 * We just use the first codec of the source connection (conn_src) */
 | 
				
			||||||
 | 
						OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
 | 
						if (!cset_dst || cset_dst->codecs_assigned == 0) {
 | 
				
			||||||
 | 
							if (cset_src->codecs_assigned >= 1) {
 | 
				
			||||||
 | 
								cset_src->codec = &cset_src->codecs[0];
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case
 | 
				
			||||||
 | 
						 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be
 | 
				
			||||||
 | 
						 * required. */
 | 
				
			||||||
 | 
						for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src);
 | 
				
			||||||
 | 
							if (codec_cset_dst) {
 | 
				
			||||||
 | 
								/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both
 | 
				
			||||||
 | 
								 * sides. We now set this codec on both connections. */
 | 
				
			||||||
 | 
								cset_dst->codec = codec_cset_dst;
 | 
				
			||||||
 | 
								cset_src->codec = codec_cset_src;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able
 | 
				
			||||||
 | 
						 * to convert. */
 | 
				
			||||||
 | 
						for (i = 0; i < cset_src->codecs_assigned; i++) {
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i];
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src);
 | 
				
			||||||
 | 
							if (codec_cset_dst) {
 | 
				
			||||||
 | 
								/* We found the a codec that we can convert to. Set each side to its codec. */
 | 
				
			||||||
 | 
								cset_dst->codec = codec_cset_dst;
 | 
				
			||||||
 | 
								cset_src->codec = codec_cset_src;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cset_dst->codecs_assigned)
 | 
				
			||||||
 | 
							cset_dst->codec = &cset_dst->codecs[0];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return codec_dst->payload_type;
 | 
						if (cset_src->codecs_assigned)
 | 
				
			||||||
 | 
							cset_src->codec = &cset_src->codecs[0];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (codec->param_present == false)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (!codec->param.amr_octet_aligned_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Find the payload type number configured for a specific codec by SDP.
 | 
					/* Find the payload type number configured for a specific codec by SDP.
 | 
				
			||||||
@@ -444,20 +476,40 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
 * \param subtype_name  SDP codec name without parameters (e.g. "AMR").
 | 
					 * \param subtype_name  SDP codec name without parameters (e.g. "AMR").
 | 
				
			||||||
 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
					 * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
 | 
				
			||||||
 *                  with incrementing match_nr.
 | 
					 *                  with incrementing match_nr.
 | 
				
			||||||
 * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found.
 | 
					 * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */
 | 
				
			||||||
 */
 | 
					const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset,
 | 
				
			||||||
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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < conn->end.codecs_assigned; i++) {
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
		if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
 | 
							if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) {
 | 
				
			||||||
			if (match_nr) {
 | 
								if (match_nr) {
 | 
				
			||||||
				match_nr--;
 | 
									match_nr--;
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return &conn->end.codecs[i];
 | 
								return &cset->codecs[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Lookup a codec that is assigned to a connection by its payload type number.
 | 
				
			||||||
 | 
					 *  \param[in] cset related codec set.
 | 
				
			||||||
 | 
					 *  \param[in] payload_type number of the codec to look up.
 | 
				
			||||||
 | 
					 *  \returns pointer to codec struct on success, NULL on failure. */
 | 
				
			||||||
 | 
					struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec = NULL;
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < cset->codecs_assigned; i++) {
 | 
				
			||||||
 | 
							if (payload_type == cset->codecs[i].payload_type) {
 | 
				
			||||||
 | 
								codec = &cset->codecs[i];
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return codec;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,12 +30,14 @@
 | 
				
			|||||||
#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>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "conn_rtp",
 | 
						.group_name_prefix = "conn_rtp",
 | 
				
			||||||
	.group_description = "rtp connection statistics",
 | 
						.group_description = "rtp connection statistics",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -71,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* ensure that the generated conn_id is unique
 | 
							/* ensure that the generated conn_id is unique
 | 
				
			||||||
		 * for this endpoint */
 | 
							 * for this endpoint */
 | 
				
			||||||
		if (!mgcp_conn_get_rtp(endp, id_hex)) {
 | 
							if (!mgcp_endp_get_conn_rtp(endp, id_hex)) {
 | 
				
			||||||
			osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
 | 
								osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN);
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -85,42 +88,31 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
				
			|||||||
/* Initialize rtp connection struct with default values */
 | 
					/* Initialize rtp connection struct with default values */
 | 
				
			||||||
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
					static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
					 | 
				
			||||||
	/* FIXME: Each new rate counter group requires an unique index. At the
 | 
						/* FIXME: Each new rate counter group requires an unique index. At the
 | 
				
			||||||
	 * moment we generate this index using this counter, but perhaps there
 | 
						 * moment we generate this index using this counter, but perhaps there
 | 
				
			||||||
	 * is a more concious way to assign the indexes. */
 | 
						 * is a more concious way to assign the indexes. */
 | 
				
			||||||
	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 = 0;
 | 
						/* Osmux specific defaults, only used if conn is later on Osmux-enabled: */
 | 
				
			||||||
 | 
						conn_rtp->osmux.state = OSMUX_STATE_DISABLED;
 | 
				
			||||||
 | 
						conn_rtp->osmux.local_cid_allocated = false;
 | 
				
			||||||
 | 
						conn_rtp->osmux.local_cid = 0;
 | 
				
			||||||
 | 
						conn_rtp->osmux.remote_cid_present = false;
 | 
				
			||||||
 | 
						conn_rtp->osmux.remote_cid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* backpointer to the generic part of the connection */
 | 
						/* backpointer to the generic part of the connection */
 | 
				
			||||||
	conn->u.rtp.conn = conn;
 | 
						conn->u.rtp.conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	end->rtp.fd = -1;
 | 
						conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
				
			||||||
	end->rtcp.fd = -1;
 | 
						if (!conn_rtp->ctrg)
 | 
				
			||||||
	end->rtp_port = end->rtcp_port = 0;
 | 
					 | 
				
			||||||
	talloc_free(end->fmtp_extra);
 | 
					 | 
				
			||||||
	end->fmtp_extra = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Set default values */
 | 
					 | 
				
			||||||
	end->frames_per_packet = 0;	/* unknown */
 | 
					 | 
				
			||||||
	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
					 | 
				
			||||||
	end->output_enabled = 0;
 | 
					 | 
				
			||||||
	end->maximum_packet_time = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);
 | 
					 | 
				
			||||||
	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->ctrg, 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->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	rate_ctr_index++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
					 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_rtp_end_init(&conn_rtp->end, conn_rtp);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,21 +121,22 @@ 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);
 | 
				
			||||||
	mgcp_free_rtp_port(&conn_rtp->end);
 | 
						if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
				
			||||||
	rate_ctr_group_free(conn_rtp->rate_ctr_group);
 | 
							mgcp_conn_iuup_cleanup(conn_rtp);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_rtp_end_cleanup(&conn_rtp->end);
 | 
				
			||||||
 | 
						rate_ctr_group_free(conn_rtp->ctrg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_conn_watchdog_cb(void *data)
 | 
					void mgcp_conn_watchdog_cb(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn = data;
 | 
						struct mgcp_conn *conn = data;
 | 
				
			||||||
	LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
						LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
				
			||||||
	mgcp_conn_free(conn->endp, conn->id);
 | 
						mgcp_conn_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int timeout = conn->endp->cfg->conn_timeout;
 | 
						int timeout = conn->endp->trunk->cfg->conn_timeout;
 | 
				
			||||||
	if (!timeout)
 | 
						if (!timeout)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,8 +156,8 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do not allow more then two connections */
 | 
						/* Do not allow more than the maximum number of connections */
 | 
				
			||||||
	if (llist_count(&endp->conns) >= endp->type->max_conns)
 | 
						if (endp->type->max_conns > 0 && llist_count(&endp->conns) >= endp->type->max_conns)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Create new connection and add it to the list */
 | 
						/* Create new connection and add it to the list */
 | 
				
			||||||
@@ -204,62 +197,10 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return conn;
 | 
						return conn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! find a connection by its ID.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 | 
				
			||||||
 *  \param[in] id identification number of the connection
 | 
					 | 
				
			||||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
					 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
	const char *id_upper;
 | 
					 | 
				
			||||||
	const char *conn_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!id || !*id)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Ignore leading zeros in needle */
 | 
					 | 
				
			||||||
	while (*id == '0')
 | 
					 | 
				
			||||||
		id++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
					 | 
				
			||||||
	 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
					 | 
				
			||||||
	 * we sent upper case hex in the CRCX response. */
 | 
					 | 
				
			||||||
	id_upper = osmo_str_toupper(id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
					 | 
				
			||||||
		/* Ignore leading zeros in haystack */
 | 
					 | 
				
			||||||
		for (conn_id=conn->id; *conn_id == '0'; conn_id++);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (strcmp(conn_id, id_upper) == 0)
 | 
					 | 
				
			||||||
			return conn;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! find an RTP connection by its ID.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 | 
				
			||||||
 *  \param[in] id identification number of the connection
 | 
					 | 
				
			||||||
 *  \returns pointer to allocated connection, NULL if not found */
 | 
					 | 
				
			||||||
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
					const char *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn = mgcp_conn_get(endp, id);
 | 
					 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
					 | 
				
			||||||
		return &conn->u.rtp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
					static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
	struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
						struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (all_stats == NULL || conn_stats == NULL)
 | 
						if (all_stats == NULL || conn_stats == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -270,29 +211,29 @@ 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
 | 
				
			||||||
 *  \param[in] endp associated endpoint
 | 
					 *  \param[in] conn the conn to free. May be NULL.
 | 
				
			||||||
 *  \param[in] id identification number of the connection */
 | 
					*/
 | 
				
			||||||
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
					void mgcp_conn_free(struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = mgcp_conn_get(endp, id);
 | 
					 | 
				
			||||||
	if (!conn)
 | 
						if (!conn)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		aggregate_rtp_conn_stats(endp, &conn->u.rtp);
 | 
							conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		mgcp_rtp_conn_cleanup(&conn->u.rtp);
 | 
							aggregate_rtp_conn_stats(conn->endp, conn_rtp);
 | 
				
			||||||
 | 
							mgcp_rtp_conn_cleanup(conn_rtp);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* NOTE: This should never be called with an
 | 
							/* NOTE: This should never be called with an
 | 
				
			||||||
@@ -302,40 +243,40 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_timer_del(&conn->watchdog);
 | 
						osmo_timer_del(&conn->watchdog);
 | 
				
			||||||
	mgcp_endp_remove_conn(endp, conn);
 | 
						mgcp_endp_remove_conn(conn->endp, conn);
 | 
				
			||||||
	/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
						/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
				
			||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! free oldest connection in the list.
 | 
					/*! Parse connection mode.
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 *  \param[in] conn Connection whose mode is being set
 | 
				
			||||||
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
 | 
					 *  \param[in] mode Mode to set
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on error */
 | 
				
			||||||
 | 
					int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
						if (mode == MGCP_CONN_NONE) {
 | 
				
			||||||
 | 
							LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "missing connection mode\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						conn->mode = mode;
 | 
				
			||||||
 | 
						LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
				
			||||||
 | 
							 mgcp_cmode_name(mode), conn->mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_empty(&endp->conns))
 | 
						/* Special handling for RTP connections */
 | 
				
			||||||
		return;
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
 | 
							struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
							conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
				
			||||||
	if (!conn)
 | 
							LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
				
			||||||
		return;
 | 
								 conn_rtp->end.output_enabled);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	mgcp_conn_free(endp, conn->id);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! free all connections at once.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 | 
				
			||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_tmp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Drop all items in the list */
 | 
					 | 
				
			||||||
	llist_for_each_entry_safe(conn, conn_tmp, &endp->conns, entry) {
 | 
					 | 
				
			||||||
		mgcp_conn_free(endp, conn->id);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return;
 | 
						/* The VTY might change the connection mode at any time, so we have
 | 
				
			||||||
 | 
						 * to hold a copy of the original connection mode */
 | 
				
			||||||
 | 
						conn->mode_orig = conn->mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dump basic connection information to human readable string.
 | 
					/*! dump basic connection information to human readable string.
 | 
				
			||||||
@@ -345,29 +286,39 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
						static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) };
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn)
 | 
				
			||||||
		snprintf(str, sizeof(str), "(null connection)");
 | 
							return "NULL";
 | 
				
			||||||
		return str;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		/* Dump RTP connection */
 | 
							conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
							OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u",
 | 
				
			||||||
			 "rtp:%u rtcp:%u)",
 | 
									   conn->name,
 | 
				
			||||||
			 conn->name,
 | 
									   mgcp_conn_rtp_type_name(conn->type),
 | 
				
			||||||
			 conn->id,
 | 
									   conn->id,
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
									   osmo_sockaddr_ntop(&conn_rtp->end.addr.u.sa, ipbuf) ? : "NULL",
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtp_port),
 | 
									   osmo_sockaddr_port(&conn_rtp->end.addr.u.sa),
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtcp_port));
 | 
									   conn_rtp->end.local_addr ? : "NULL",
 | 
				
			||||||
 | 
									   conn_rtp->end.local_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (conn_rtp->type) {
 | 
				
			||||||
 | 
							case MGCP_RTP_OSMUX:
 | 
				
			||||||
 | 
								OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_rtp->osmux.local_cid);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OSMO_STRBUF_PRINTF(sb, ")");
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* Should not happen, we should be able to dump
 | 
							/* Should not happen, we should be able to dump
 | 
				
			||||||
		 * every possible connection type. */
 | 
							 * every possible connection type. */
 | 
				
			||||||
		snprintf(str, sizeof(str), "(unknown connection type)");
 | 
							return "(unknown connection type)";
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return str;
 | 
						return str;
 | 
				
			||||||
@@ -395,12 +346,9 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! get oldest connection in the list.
 | 
					const struct value_string mgcp_conn_rtp_type_names[] = {
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
						{ MGCP_RTP_DEFAULT, "rtp" },
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
 | 
						{ MGCP_RTP_OSMUX, "osmux" },
 | 
				
			||||||
{
 | 
						{ MGCP_RTP_IUUP, "iuup" },
 | 
				
			||||||
	if (llist_empty(&endp->conns))
 | 
						{}
 | 
				
			||||||
		return NULL;
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
					 | 
				
			||||||
 * All Rights Reserved
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU Affero General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU Affero General Public License
 | 
					 | 
				
			||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/ctrl/control_if.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
 | 
					 | 
				
			||||||
				void **node_data, int *i)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
					 | 
				
			||||||
					     const char *bind_addr, uint16_t port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
 | 
					 | 
				
			||||||
					   _LAST_CTRL_NODE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -56,133 +56,147 @@ static const struct e1inp_line_ops dummy_e1_line_ops = {
 | 
				
			|||||||
	.sign_link = NULL,
 | 
						.sign_link = NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* EFR idle frame */
 | 
					/* The following EFR TRAU-DL frame is a dummy to be transmitted in the absence
 | 
				
			||||||
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * of RTP-derived TRAU-DL frames.  The payload bit content here is the decoder
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * homing frame (DHF) of TS 46.060 section 8.2 Table 7 - the best we can do
 | 
				
			||||||
				      1, 1, 1, 0, 1, 0, 0, 0,
 | 
					 * in the absence of a proper TFO transform for EFR - while the full TRAU-DL
 | 
				
			||||||
				      0, 0, 0, 0, 1, 0, 0, 0,
 | 
					 * frame was generated by passing said EFR DHF through osmo_rtp2trau().
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
					 */
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_efr[] = {
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 0, 1, 1, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 0, 1, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 0, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 1, 1, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 0, 1,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 0, 1, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				      0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 0,
 | 
				
			||||||
				      1, 0, 0, 0, 0, 0, 1, 0,
 | 
						1, 1, 1, 0, 1, 0, 1, 1,
 | 
				
			||||||
				      1, 1, 1, 1, 1, 1, 1, 1,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* FR idle frame */
 | 
					/* The following FRv1 TRAU-DL frame is a dummy to be transmitted in the absence
 | 
				
			||||||
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * of RTP-derived TRAU-DL frames.  The payload bit content here is the silence
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * frame of TS 46.011 Table 1 - the best we can do without integrating the
 | 
				
			||||||
				     1, 1, 1, 1, 0, 0, 0, 0,
 | 
					 * TFO transform for FRv1 from Themyscira libgsmfr2 - while the full TRAU-DL
 | 
				
			||||||
				     0, 0, 0, 0, 1, 0, 0, 0,
 | 
					 * frame was generated by passing said FRv1 silence frame through
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
					 * osmo_rtp2trau().
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
					 */
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_fr[] = {
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 1, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 1, 1, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 0, 0, 1, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 0, 1, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 1, 1, 0, 0, 0, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 1, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 1, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 0, 1, 1, 1, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 0, 1, 1, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 0, 0, 1, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 0, 1, 0, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 1, 1, 0, 1, 1, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 1, 1, 0, 0, 0, 1,
 | 
				
			||||||
				     0, 0, 0, 0, 0, 0, 0, 0,
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
				     1, 0, 0, 0, 0, 0, 1, 0,
 | 
						1, 0, 0, 0, 0, 1, 0, 1,
 | 
				
			||||||
				     1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
						0, 0, 0, 0, 1, 1, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
 | 
						1, 0, 0, 1, 1, 1, 0, 1,
 | 
				
			||||||
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
 | 
						0, 0, 0, 1, 0, 0, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 0, 1, 1, 0, 1, 1,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
 | 
					/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
 | 
				
			||||||
static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
					static const ubit_t idle_tf_spch[] = {
 | 
				
			||||||
				       0, 0, 0, 0, 0, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				       1, 0, 1, 1, 1, 0, 0, 0,
 | 
						0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
				       0, 0, 0, 0, 1, 0, 0, 0,
 | 
						1, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						0, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 0,
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
				       1, 1, 1, 1, 1, 1, 1, 1,
 | 
						1, 1, 1, 1, 1, 1, 1, 0,
 | 
				
			||||||
 | 
						1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
 | 
					/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
 | 
				
			||||||
@@ -192,12 +206,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;
 | 
				
			||||||
@@ -222,7 +236,7 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
 | 
				
			|||||||
	osmo_i460_mux_enqueue(endp->e1.schan, msg);
 | 
						osmo_i460_mux_enqueue(endp->e1.schan, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */
 | 
					/* called by I.460 de-multiplexer; feed output of I.460 demux into TRAU frame sync */
 | 
				
			||||||
static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
 | 
					static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
 | 
				
			||||||
				  unsigned int num_bits)
 | 
									  unsigned int num_bits)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -238,9 +252,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;
 | 
				
			||||||
@@ -301,18 +315,17 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
 | 
						mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
skip:
 | 
					skip:
 | 
				
			||||||
	rate_ctr_inc(&rate_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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Function to handle outgoing E1 traffic */
 | 
					/* handle outgoing E1 traffic */
 | 
				
			||||||
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
					static void e1_send_ts_frame(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 */
 | 
				
			||||||
@@ -325,7 +338,7 @@ static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
				
			|||||||
				     msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
									     msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	/* Hand data over to the E1 stack */
 | 
						/* Hand data over to the E1 stack */
 | 
				
			||||||
	msgb_enqueue(&ts->raw.tx_queue, msg);
 | 
						e1inp_ts_send_raw(ts, msg);
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -337,7 +350,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -358,16 +372,17 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
	osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
 | 
						osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Trigger sending of pending E1 traffic */
 | 
						/* Trigger sending of pending E1 traffic */
 | 
				
			||||||
	e1_send(ts, trunk);
 | 
						e1_send_ts_frame(ts, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* e1inp_rx_ts(), the caller of this callback does not free() msgb. */
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
					static int e1_open(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*! Each timeslot needs only to be configured once. The Timeslot then
 | 
						/*! One E1 timeslot may serve multiple I.460 subslots. The timeslot is opened as soon as an I.460 subslot is
 | 
				
			||||||
	 *  stays open and permanently receives data. It is then up to the
 | 
						 *  opened and will stay open until the last I.460 subslot is closed (see e1_close below). This function must
 | 
				
			||||||
	 *  I.460 demultiplexer to add/remove subchannels as needed. It is
 | 
						 *  be called any time a new I.460 subslot is opened in order to maintain constancy of the ts_usecount counter. */
 | 
				
			||||||
	 *  allowed to call this function multiple times since we check if the
 | 
					 | 
				
			||||||
	 *  timeslot is already configured. */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct e1inp_line *e1_line;
 | 
						struct e1inp_line *e1_line;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -375,15 +390,17 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
	OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
						OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
				
			||||||
	cfg = trunk->cfg;
 | 
						cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trunk->e1.ts_in_use[ts_nr - 1]) {
 | 
						if (trunk->e1.ts_usecount[ts_nr - 1] > 0) {
 | 
				
			||||||
		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 and in use by %u subslot(s), using it as it is...\n",
 | 
				
			||||||
 | 
								  ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
 | 
				
			||||||
 | 
							trunk->e1.ts_usecount[ts_nr - 1]++;
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Get E1 line */
 | 
						/* Find 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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -397,12 +414,61 @@ static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	rc = e1inp_line_update(e1_line);
 | 
						rc = e1inp_line_update(e1_line);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", 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_usecount[ts_nr - 1]++;
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int e1_close(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* See also comment above (e1_open). This function must be called any time an I.460 subslot is closed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct e1inp_line *e1_line;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
				
			||||||
 | 
						cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (trunk->e1.ts_usecount[ts_nr - 1] > 1) {
 | 
				
			||||||
 | 
							trunk->e1.ts_usecount[ts_nr - 1]--;
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u still in use by %u other subslot(s), leaving it open...\n",
 | 
				
			||||||
 | 
								  ts_nr, trunk->e1.ts_usecount[ts_nr - 1]);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						} else if (trunk->e1.ts_usecount[ts_nr - 1] == 0) {
 | 
				
			||||||
 | 
							/* This should not be as it means we close the timeslot too often. */
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "E1 timeslot %u already closed, leaving it as it is...\n", ts_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find E1 line */
 | 
				
			||||||
 | 
						e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
				
			||||||
 | 
						if (!e1_line) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
 | 
				
			||||||
 | 
								  trunk->e1.vty_line_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Release E1 timeslot */
 | 
				
			||||||
 | 
						rc = e1inp_ts_config_none(&e1_line->ts[ts_nr - 1], e1_line);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to disable E1 timeslot %u.\n", ts_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc = e1inp_line_update(e1_line);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 line %u.\n", trunk->e1.vty_line_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u closed.\n", ts_nr);
 | 
				
			||||||
 | 
						trunk->e1.ts_usecount[ts_nr - 1]--;
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk->e1.ts_usecount[ts_nr - 1] == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -413,11 +479,21 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
		return OSMO_TRAU16_FT_FR;
 | 
							return OSMO_TRAU16_FT_FR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
		return OSMO_TRAU16_FT_EFR;
 | 
							return OSMO_TRAU16_FT_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
					
 | 
				
			||||||
		return OSMO_TRAU16_FT_HR;
 | 
						if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
							if (i460_rate == OSMO_I460_RATE_16k)
 | 
				
			||||||
 | 
								return OSMO_TRAU16_FT_HR;
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k)
 | 
				
			||||||
 | 
								return OSMO_TRAU8_SPEECH;
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
 | 
				
			||||||
 | 
							return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
		if (i460_rate == OSMO_I460_RATE_8k) {
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
			switch (amr_ft) {
 | 
								switch (amr_ft) {
 | 
				
			||||||
			case AMR_4_75:
 | 
								case AMR_4_75:
 | 
				
			||||||
@@ -435,11 +511,11 @@ static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return OSMO_TRAU16_FT_AMR;
 | 
							return OSMO_TRAU16_FT_AMR;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
					 | 
				
			||||||
			 sdp_subtype_name);
 | 
					 | 
				
			||||||
		return OSMO_TRAU_FT_NONE;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
							 sdp_subtype_name);
 | 
				
			||||||
 | 
						return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Determine a suitable TRAU frame type for a given codec */
 | 
					/* Determine a suitable TRAU frame type for a given codec */
 | 
				
			||||||
@@ -448,11 +524,21 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
					
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_8_HR;
 | 
						if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0) {
 | 
				
			||||||
	else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
							if (i460_rate == OSMO_I460_RATE_16k)
 | 
				
			||||||
 | 
								return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k)
 | 
				
			||||||
 | 
								return OSMO_TRAU_SYNCP_8_HR;
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "E1-TRAU-TX: unsupported or illegal I.460 rate for HR\n");
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
		if (i460_rate == OSMO_I460_RATE_8k) {
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
			switch (amr_ft) {
 | 
								switch (amr_ft) {
 | 
				
			||||||
			case AMR_4_75:
 | 
								case AMR_4_75:
 | 
				
			||||||
@@ -470,11 +556,11 @@ static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
					 | 
				
			||||||
			 sdp_subtype_name);
 | 
					 | 
				
			||||||
		return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
							 sdp_subtype_name);
 | 
				
			||||||
 | 
						return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Find out if a given TRAU frame type is AMR */
 | 
					/* Find out if a given TRAU frame type is AMR */
 | 
				
			||||||
@@ -492,7 +578,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* !Equip E1 endpoint with I.460 mux resources.
 | 
					/*! Equip E1 endpoint with I.460 mux and E1 timeslot resources.
 | 
				
			||||||
 *  \param[in] endp endpoint to equip
 | 
					 *  \param[in] endp endpoint to equip
 | 
				
			||||||
 *  \param[in] ts E1 timeslot number.
 | 
					 *  \param[in] ts E1 timeslot number.
 | 
				
			||||||
 *  \param[in] ss E1 subslot number.
 | 
					 *  \param[in] ss E1 subslot number.
 | 
				
			||||||
@@ -513,7 +599,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
				
			|||||||
	endp->e1.last_amr_ft = AMR_4_75;
 | 
						endp->e1.last_amr_ft = AMR_4_75;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set up E1 line / timeslot */
 | 
						/* Set up E1 line / timeslot */
 | 
				
			||||||
	rc = e1_init(endp->trunk, ts);
 | 
						rc = e1_open(endp->trunk, ts);
 | 
				
			||||||
	if (rc != 0)
 | 
						if (rc != 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -545,7 +631,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) {
 | 
				
			||||||
@@ -578,15 +664,17 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
 | 
				
			|||||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_rtp;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	enum osmo_tray_sync_pat_id sync_pat_id;
 | 
						enum osmo_tray_sync_pat_id sync_pat_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In order to determine the codec, find the oldest connection on
 | 
						/* In order to determine the codec, find the oldest connection on
 | 
				
			||||||
	 * the endpoint and use its codec information. Normally on an E1
 | 
						 * the endpoint and use its codec information. Normally on an E1
 | 
				
			||||||
	 * endpoint no more than one connection should exist. */
 | 
						 * endpoint no more than one connection should exist. */
 | 
				
			||||||
	conn = mgcp_conn_get_oldest(endp);
 | 
						conn = mgcp_endp_get_conn_oldest(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	codec = conn->u.rtp.end.codec;
 | 
						conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
						codec = conn_rtp->end.cset.codec;
 | 
				
			||||||
	OSMO_ASSERT(codec);
 | 
						OSMO_ASSERT(codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Update codec information */
 | 
						/* Update codec information */
 | 
				
			||||||
@@ -600,9 +688,15 @@ void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Remove E1 resources from endpoint
 | 
					/*! Remove E1 resources from endpoint
 | 
				
			||||||
 *  \param[in] endp endpoint to release. */
 | 
					 *  \param[in] endp endpoint to release.
 | 
				
			||||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
 | 
					 *  \param[in] ts E1 timeslot number. */
 | 
				
			||||||
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp, uint8_t ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* Guard against multiple calls. In case we don't see a subchannel anymore we can safely assume that all work
 | 
				
			||||||
 | 
						 * is done. */
 | 
				
			||||||
 | 
						if (!(endp->e1.schan || endp->e1.trau_rtp_st || endp->e1.trau_sync_fi))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (endp->e1.schan)
 | 
						if (endp->e1.schan)
 | 
				
			||||||
@@ -611,8 +705,10 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
		talloc_free(endp->e1.trau_rtp_st);
 | 
							talloc_free(endp->e1.trau_rtp_st);
 | 
				
			||||||
	if (endp->e1.trau_sync_fi)
 | 
						if (endp->e1.trau_sync_fi)
 | 
				
			||||||
		osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
 | 
							osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&endp->e1, 0, sizeof(endp->e1));
 | 
						memset(&endp->e1, 0, sizeof(endp->e1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Close E1 timeslot */
 | 
				
			||||||
 | 
						e1_close(endp->trunk, ts);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
 | 
					/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
 | 
				
			||||||
@@ -622,7 +718,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 +775,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
 | 
				
			||||||
@@ -37,7 +38,6 @@
 | 
				
			|||||||
const struct mgcp_endpoint_typeset ep_typeset = {
 | 
					const struct mgcp_endpoint_typeset ep_typeset = {
 | 
				
			||||||
	/* Specify endpoint properties for RTP endpoint */
 | 
						/* Specify endpoint properties for RTP endpoint */
 | 
				
			||||||
	.rtp = {
 | 
						.rtp = {
 | 
				
			||||||
		.max_conns = 2,
 | 
					 | 
				
			||||||
		.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
							.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
				
			||||||
		.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
 | 
							.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -58,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Generate E1 endpoint name from given numeric parameters */
 | 
					/* Generate E1 endpoint name from given numeric parameters */
 | 
				
			||||||
static char *gen_e1_epname(void *ctx, const char *domain, uint8_t trunk_nr,
 | 
					static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr,
 | 
				
			||||||
			   uint8_t ts_nr, uint8_t ss_nr)
 | 
								   uint8_t ts_nr, uint8_t ss_nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int rate;
 | 
						unsigned int rate;
 | 
				
			||||||
@@ -88,7 +88,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) {
 | 
				
			||||||
@@ -110,31 +109,6 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
 | 
				
			|||||||
	return endp;
 | 
						return endp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! release endpoint, all open connections are closed.
 | 
					 | 
				
			||||||
 *  \param[in] endp endpoint to release */
 | 
					 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Normally this function should only be called when
 | 
					 | 
				
			||||||
	 * all connections have been removed already. In case
 | 
					 | 
				
			||||||
	 * that there are still connections open (e.g. when
 | 
					 | 
				
			||||||
	 * RSIP is executed), free them all at once. */
 | 
					 | 
				
			||||||
	mgcp_conn_free_all(endp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Reset endpoint parameters and states */
 | 
					 | 
				
			||||||
	talloc_free(endp->callid);
 | 
					 | 
				
			||||||
	endp->callid = NULL;
 | 
					 | 
				
			||||||
	talloc_free(endp->local_options.string);
 | 
					 | 
				
			||||||
	endp->local_options.string = NULL;
 | 
					 | 
				
			||||||
	talloc_free(endp->local_options.codec);
 | 
					 | 
				
			||||||
	endp->local_options.codec = NULL;
 | 
					 | 
				
			||||||
	endp->wildcarded_req = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
 | 
					 | 
				
			||||||
		mgcp_e1_endp_release(endp);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
 | 
					/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
 | 
				
			||||||
 * "ds/e1-") and write the epname without the prefix back to the memory
 | 
					 * "ds/e1-") and write the epname without the prefix back to the memory
 | 
				
			||||||
 * pointed at by epname. (per trunk the prefix is the same for all endpoints,
 | 
					 * pointed at by epname. (per trunk the prefix is the same for all endpoints,
 | 
				
			||||||
@@ -182,12 +156,15 @@ 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 +191,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 +204,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 +216,29 @@ 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Check if the given epname refers to a "null" endpoint.
 | 
				
			||||||
 | 
					 *  \param[in] epname endpoint name to check
 | 
				
			||||||
 | 
					 *  \returns true if epname refers to "null"" endpoint, else false. */
 | 
				
			||||||
 | 
					bool mgcp_endp_is_null(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strncasecmp(epname, "null@", 5) == 0)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Find an endpoint by its name on a specified trunk.
 | 
					/*! Find an endpoint by its name on a specified trunk.
 | 
				
			||||||
 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
					 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
				
			||||||
 *  \param[in] epname endpoint name to lookup.
 | 
					 *  \param[in] epname endpoint name to lookup.
 | 
				
			||||||
@@ -253,13 +255,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 +274,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 +291,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 +314,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) {
 | 
				
			||||||
@@ -476,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname)
 | 
				
			|||||||
/* Check if the selected E1 endpoint is avalable, which means that none of
 | 
					/* Check if the selected E1 endpoint is avalable, which means that none of
 | 
				
			||||||
 * the overlapping endpoints are currently serving a call. (if the system
 | 
					 * the overlapping endpoints are currently serving a call. (if the system
 | 
				
			||||||
 * is properly configured such a situation should never ocurr!) */
 | 
					 * is properly configured such a situation should never ocurr!) */
 | 
				
			||||||
static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
					static bool endp_avail_e1(const struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* The following map shows the overlapping of the subslots and their
 | 
						/* The following map shows the overlapping of the subslots and their
 | 
				
			||||||
	 * respective rates. The numbers on the right running from top to bottom
 | 
						 * respective rates. The numbers on the right running from top to bottom
 | 
				
			||||||
@@ -555,7 +525,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",
 | 
				
			||||||
@@ -582,7 +552,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp)
 | 
				
			|||||||
/*! check if an endpoint is available for any kind of operation.
 | 
					/*! check if an endpoint is available for any kind of operation.
 | 
				
			||||||
 *  \param[in] endp endpoint to check.
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 *  \returns true if endpoint is avalable, false it is blocked for any reason. */
 | 
					 *  \returns true if endpoint is avalable, false it is blocked for any reason. */
 | 
				
			||||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
					bool mgcp_endp_avail(const struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (endp->trunk->trunk_type) {
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
	case MGCP_TRUNK_VIRTUAL:
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
@@ -599,6 +569,24 @@ bool mgcp_endp_avail(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get number of conns in an endpoint.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 | 
					 *  \returns Number of connections present in the endpoint. */
 | 
				
			||||||
 | 
					unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return llist_count(&endp->conns);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! check if an endpoint can in current state allocate new conns.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to check.
 | 
				
			||||||
 | 
					 *  \returns true if more connections can be allowed on endpoint, false if it is already busy. */
 | 
				
			||||||
 | 
					bool mgcp_endp_is_full(const struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (endp->type->max_conns == 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return mgcp_endp_num_conns(endp) >= endp->type->max_conns;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
					/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
				
			||||||
 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
					 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
				
			||||||
 *  created.
 | 
					 *  created.
 | 
				
			||||||
@@ -619,6 +607,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) {
 | 
				
			||||||
@@ -682,3 +672,127 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
				
			|||||||
	if (llist_empty(&endp->conns))
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
		mgcp_endp_release(endp);
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free oldest connection in the list.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
				
			||||||
 | 
						mgcp_conn_free(conn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free all connections at once.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					#if defined(__has_attribute)
 | 
				
			||||||
 | 
					#if __has_attribute(no_sanitize)
 | 
				
			||||||
 | 
					__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Drop all items in the list, might be consecutive! */
 | 
				
			||||||
 | 
						while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
 | 
				
			||||||
 | 
							mgcp_conn_free(conn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! find a connection by its ID.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint
 | 
				
			||||||
 | 
					 *  \param[in] id identification number of the connection
 | 
				
			||||||
 | 
					 *  \returns pointer to allocated connection, NULL if not found */
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
						const char *id_upper;
 | 
				
			||||||
 | 
						const char *conn_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!id || !*id)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Ignore leading zeros in needle */
 | 
				
			||||||
 | 
						while (*id == '0')
 | 
				
			||||||
 | 
							id++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of
 | 
				
			||||||
 | 
						 * Connections" defines the id as a hex string, so clients may return lower case hex even though
 | 
				
			||||||
 | 
						 * we sent upper case hex in the CRCX response. */
 | 
				
			||||||
 | 
						id_upper = osmo_str_toupper(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
 | 
							/* Ignore leading zeros in haystack */
 | 
				
			||||||
 | 
							for (conn_id = conn->id; *conn_id == '0'; conn_id++);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(conn_id, id_upper) == 0)
 | 
				
			||||||
 | 
								return conn;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! get oldest connection in the list.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
 | 
					struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! find an RTP connection by its ID.
 | 
				
			||||||
 | 
					 *  \param[in] endp associated endpoint
 | 
				
			||||||
 | 
					 *  \param[in] id identification number of the connection
 | 
				
			||||||
 | 
					 *  \returns pointer to allocated connection, NULL if not found */
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										const char *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = mgcp_endp_get_conn(endp, id);
 | 
				
			||||||
 | 
						if (!conn)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
				
			||||||
 | 
							return mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! release endpoint, all open connections are closed.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to release */
 | 
				
			||||||
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Normally this function should only be called when
 | 
				
			||||||
 | 
						 * all connections have been removed already. In case
 | 
				
			||||||
 | 
						 * that there are still connections open (e.g. when
 | 
				
			||||||
 | 
						 * RSIP is executed), free them all at once. */
 | 
				
			||||||
 | 
						mgcp_endp_free_conn_all(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We must only decrement the stat item when the endpoint as actually
 | 
				
			||||||
 | 
						 * claimed. An endpoint is claimed when a call-id is set */
 | 
				
			||||||
 | 
						if (endp->callid)
 | 
				
			||||||
 | 
							osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
 | 
				
			||||||
 | 
													 TRUNK_STAT_ENDPOINTS_USED), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reset endpoint parameters and states */
 | 
				
			||||||
 | 
						talloc_free(endp->callid);
 | 
				
			||||||
 | 
						endp->callid = NULL;
 | 
				
			||||||
 | 
						talloc_free(endp->local_options.string);
 | 
				
			||||||
 | 
						endp->local_options.string = NULL;
 | 
				
			||||||
 | 
						talloc_free(endp->local_options.codec);
 | 
				
			||||||
 | 
						endp->local_options.codec = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (endp->trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
				
			||||||
 | 
							uint8_t ts = e1_ts_nr_from_epname(endp->name);
 | 
				
			||||||
 | 
							mgcp_e1_endp_release(endp, ts);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										755
									
								
								src/libosmo-mgcp/mgcp_iuup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										755
									
								
								src/libosmo-mgcp/mgcp_iuup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,755 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (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;
 | 
				
			||||||
 | 
						if (!irp) {
 | 
				
			||||||
 | 
							/* No IuUP Initialization has occured on the IuUP side yet. Return error and drop the RTP data, until
 | 
				
			||||||
 | 
							 * the IuUP Initialization has configured the link. */
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *dst_codec;
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst_codec = conn_rtp_dst->end.cset.codec;
 | 
				
			||||||
 | 
						if (mgcp_codec_amr_is_octet_aligned(dst_codec)) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR BE: ft %d, len %zd\n", ft, 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 = dst_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);
 | 
				
			||||||
 | 
						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_RTP_OSMUX:
 | 
				
			||||||
 | 
						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 rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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),
 | 
				
			||||||
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa), 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->cset.codec->rate));
 | 
				
			||||||
 | 
						hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
				
			||||||
 | 
						hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
						rtp_state->alt_rtp_tx_sequence++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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),
 | 
				
			||||||
 | 
							 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
 | 
						forward_data_tap(rtp_end->rtp, &conn_src->tap_out, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = mgcp_udp_send(rtp_end->rtp, &rtp_end->addr, (char *)hdr, buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
 | 
				
			||||||
 | 
						rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, buflen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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));
 | 
				
			||||||
 | 
						/* rtph is further filled in mgcp_send_iuup() below. */
 | 
				
			||||||
 | 
						*rtph = (struct rtp_hdr){
 | 
				
			||||||
 | 
							.csrc_count = 0,
 | 
				
			||||||
 | 
							.extension = 0,
 | 
				
			||||||
 | 
							.padding = 0,
 | 
				
			||||||
 | 
							.version = 2,
 | 
				
			||||||
 | 
							.payload_type = conn_rtp_dst->end.cset.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 = osmo_sockaddr_port(&conn_rtp_src->end.addr.u.sa);
 | 
				
			||||||
 | 
							conn_rtp_src->end.addr = *mc->from_addr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
							osmo_sockaddr_set_port(&conn_rtp_src->end.addr.u.sa, 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. Takes ownership of msg. */
 | 
				
			||||||
 | 
					int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_iuup_rnl_prim *irp;
 | 
				
			||||||
 | 
						struct rtp_hdr *rtph;
 | 
				
			||||||
 | 
						int rc = -1;
 | 
				
			||||||
 | 
						int iuup_length = 0;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *src_codec;
 | 
				
			||||||
 | 
						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 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						src_codec = conn_src_rtp->end.cset.codec;
 | 
				
			||||||
 | 
						if (strcmp(src_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",
 | 
				
			||||||
 | 
								     src_codec->subtype_name);
 | 
				
			||||||
 | 
							goto free_ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (mgcp_codec_amr_is_octet_aligned(src_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 (!osmo_amr_ft_valid(amr_hdr->ft)) {
 | 
				
			||||||
 | 
								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 ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
				
			||||||
 | 
							irp->u.data.rfci = rfci;
 | 
				
			||||||
 | 
							msgb_pull(msg, 2);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR OA -> IuUP: ft %d -> rfci %d len %d\n",
 | 
				
			||||||
 | 
							     amr_hdr->ft, rfci, msgb_length(msg));
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
 | 
				
			||||||
 | 
							int8_t ft;
 | 
				
			||||||
 | 
							uint8_t q;
 | 
				
			||||||
 | 
							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 (!osmo_amr_ft_valid(ft)) {
 | 
				
			||||||
 | 
								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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							q = amr_bwe_hdr[1] & 0x40;
 | 
				
			||||||
 | 
							irp->u.data.fqc = q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR BE -> IuUP: ft %d -> rfci %d len %d\n",
 | 
				
			||||||
 | 
							     ft, rfci, msgb_length(msg));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
@@ -31,6 +32,11 @@
 | 
				
			|||||||
#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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (same fmt as LOGPENDP()) */
 | 
				
			||||||
 | 
					#define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LEVEL, "endpoint:%s " FMT, (PDATA) ? ((PDATA)->epname ? : "null-epname") : "null-pdata", ##ARGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Display an mgcp message on the log output.
 | 
					/*! Display an mgcp message on the log output.
 | 
				
			||||||
 *  \param[in] message mgcp message string
 | 
					 *  \param[in] message mgcp message string
 | 
				
			||||||
@@ -74,82 +80,41 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Parse connection mode.
 | 
					/*! Parse connection mode.
 | 
				
			||||||
 *  \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
 | 
					 *  \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback)
 | 
				
			||||||
 *  \param[in] endp pointer to endpoint (only used for log output)
 | 
					 *  \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */
 | 
				
			||||||
 *  \param[out] associated connection to be modified accordingly
 | 
					enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode)
 | 
				
			||||||
 *  \returns 0 on success, -1 on error */
 | 
					 | 
				
			||||||
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
			 struct mgcp_conn *conn)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mode) {
 | 
						if (!mode)
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
							return MGCP_CONN_NONE;
 | 
				
			||||||
			 "missing connection mode\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	if (!endp)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(mode, "recvonly") == 0)
 | 
						if (strcasecmp(mode, "recvonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_ONLY;
 | 
							return MGCP_CONN_RECV_ONLY;
 | 
				
			||||||
	else if (strcasecmp(mode, "sendrecv") == 0)
 | 
						if (strcasecmp(mode, "sendrecv") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_SEND;
 | 
							return MGCP_CONN_RECV_SEND;
 | 
				
			||||||
	else if (strcasecmp(mode, "sendonly") == 0)
 | 
						if (strcasecmp(mode, "sendonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_SEND_ONLY;
 | 
							return MGCP_CONN_SEND_ONLY;
 | 
				
			||||||
	else if (strcasecmp(mode, "loopback") == 0)
 | 
						if (strcasecmp(mode, "confecho") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_LOOPBACK;
 | 
							return MGCP_CONN_CONFECHO;
 | 
				
			||||||
	else {
 | 
						if (strcasecmp(mode, "loopback") == 0)
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
							return MGCP_CONN_LOOPBACK;
 | 
				
			||||||
			 "unknown connection mode: '%s'\n", mode);
 | 
						return MGCP_CONN_NONE;
 | 
				
			||||||
		ret = -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Special handling for RTP connections */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
					 | 
				
			||||||
		conn->u.rtp.end.output_enabled =
 | 
					 | 
				
			||||||
		    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
					 | 
				
			||||||
		 mode, conn->mode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Special handling für RTP connections */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
					 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
 | 
					 | 
				
			||||||
			 conn->u.rtp.end.output_enabled);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The VTY might change the connection mode at any time, so we have
 | 
					 | 
				
			||||||
	 * to hold a copy of the original connection mode */
 | 
					 | 
				
			||||||
	conn->mode_orig = conn->mode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
					/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
				
			||||||
 *  \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,42 +123,104 @@ 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)) {
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
									LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n");
 | 
				
			||||||
				     "MGCP header parsing error\n");
 | 
					 | 
				
			||||||
				return -510;
 | 
									return -510;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		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++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (i != 4) {
 | 
						if (i != 4) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
 | 
							LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n");
 | 
				
			||||||
		pdata->trans = "000000";
 | 
					 | 
				
			||||||
		pdata->endp = NULL;
 | 
					 | 
				
			||||||
		return -510;
 | 
							return -510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *saveptr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						line += strlen(MGCP_X_OSMO_IGN_HEADER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							char *token = strtok_r(line, " ", &saveptr);
 | 
				
			||||||
 | 
							line = NULL;
 | 
				
			||||||
 | 
							if (!token)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!strcasecmp(token, "C"))
 | 
				
			||||||
 | 
								pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Analyze and parse the the header of an MGCP message string.
 | 
				
			||||||
 | 
					 *  \param[inout] pdata caller provided memory to store the parsing results.
 | 
				
			||||||
 | 
					 *  \returns 0 when parsing was successful, negative (MGCP cause code) on error. */
 | 
				
			||||||
 | 
					int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_parse_hdr_pars *hp = &pdata->hpars;
 | 
				
			||||||
 | 
						char *line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_parse_hdr_pars_init(hp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_line(line, pdata->save) {
 | 
				
			||||||
 | 
							if (!mgcp_check_param(line)) {
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
 | 
							case 'L':
 | 
				
			||||||
 | 
								hp->local_options = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'C':
 | 
				
			||||||
 | 
								hp->callid = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'I':
 | 
				
			||||||
 | 
								hp->connid = (const char *)line + 3;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'M':
 | 
				
			||||||
 | 
								hp->mode = mgcp_parse_conn_mode((const char *)line + 3);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'X':
 | 
				
			||||||
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
 | 
									hp->remote_osmux_cid = mgcp_parse_osmux_cid(line);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (parse_x_osmo_ign(pdata, line))
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '\0':
 | 
				
			||||||
 | 
								hp->have_sdp = true;
 | 
				
			||||||
 | 
								goto mgcp_header_done;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
				
			||||||
 | 
								return -539;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mgcp_header_done:
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
					/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
				
			||||||
 *  \param[in] line single parameter line from the MGCP message
 | 
					 *  \param[in] line single parameter line from the MGCP message
 | 
				
			||||||
 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
					 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
				
			||||||
@@ -204,42 +231,37 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
						if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
				
			||||||
		return -1;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
						if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
				
			||||||
		     line);
 | 
							     line);
 | 
				
			||||||
		return -2;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmux_cid > OSMUX_CID_MAX) {
 | 
						if (osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
				
			||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return osmux_cid;
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! 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] 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 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,
 | 
							return false;
 | 
				
			||||||
		     "Wrong MGCP option format: '%s' on %s\n",
 | 
					 | 
				
			||||||
		     line, endp->name);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 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.
 | 
				
			||||||
@@ -306,7 +328,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if connection exists */
 | 
						/* Check if connection exists */
 | 
				
			||||||
	if (mgcp_conn_get(endp, conn_id))
 | 
						if (mgcp_endp_get_conn(endp, conn_id))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												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[] = {
 | 
				
			||||||
@@ -38,7 +43,7 @@ static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
				
			|||||||
	    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
						    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mgcp",
 | 
						.group_name_prefix = "mgcp",
 | 
				
			||||||
	.group_description = "mgcp general statistics",
 | 
						.group_description = "mgcp general statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -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." },
 | 
				
			||||||
@@ -67,7 +71,7 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
						[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "crcx",
 | 
						.group_name_prefix = "crcx",
 | 
				
			||||||
	.group_description = "crxc statistics",
 | 
						.group_description = "crxc statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -90,12 +94,10 @@ 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." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mdcx",
 | 
						.group_name_prefix = "mdcx",
 | 
				
			||||||
	.group_description = "mdcx statistics",
 | 
						.group_description = "mdcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -105,19 +107,16 @@ 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." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "dlcx",
 | 
						.group_name_prefix = "dlcx",
 | 
				
			||||||
	.group_description = "dlcx statistics",
 | 
						.group_description = "dlcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -126,12 +125,12 @@ 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 = {
 | 
					static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "e1",
 | 
						.group_name_prefix = "e1",
 | 
				
			||||||
	.group_description = "e1 statistics",
 | 
						.group_description = "e1 statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -139,7 +138,7 @@ const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = e1_rate_ctr_desc
 | 
						.ctr_desc = e1_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "all_rtp_conn",
 | 
						.group_name_prefix = "all_rtp_conn",
 | 
				
			||||||
	.group_description = "aggregated statistics for all rtp connections",
 | 
						.group_description = "aggregated statistics for all rtp connections",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -147,83 +146,202 @@ 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)
 | 
					static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
 | 
				
			||||||
{
 | 
						.group_name_prefix = "all_osmux_conn",
 | 
				
			||||||
	rate_ctr_group_free(rate_ctr_group);
 | 
						.group_description = "aggregated statistics for all osmux connections",
 | 
				
			||||||
	return 0;
 | 
						.class_id = 1,
 | 
				
			||||||
}
 | 
						.num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = all_osmux_conn_rate_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate global rate counters into a given rate counter struct
 | 
					/*! allocate global rate counters
 | 
				
			||||||
 *  (called once at startup)
 | 
					 *  (called once at startup).
 | 
				
			||||||
 *  \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
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure */
 | 
					int mgcp_ratectr_global_alloc(struct mgcp_config *cfg)
 | 
				
			||||||
int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* FIXME: Each new rate counter group requires a unique index. At the
 | 
						struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
 | 
				
			||||||
	 * moment we generate an index using a counter, but perhaps there is
 | 
						static atomic_uint general_rate_ctr_index = 0;
 | 
				
			||||||
	 * a better way of assigning indices? */
 | 
						char ctr_name[512];
 | 
				
			||||||
	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;
 | 
				
			||||||
 | 
						static atomic_uint all_osmux_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) {
 | 
						if (ratectr->all_osmux_conn_stats == NULL) {
 | 
				
			||||||
		ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index);
 | 
							ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
 | 
				
			||||||
 | 
													   all_osmux_conn_rate_ctr_index++);
 | 
				
			||||||
 | 
							if (!ratectr->all_osmux_conn_stats)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_osmux_conn_stats) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->all_osmux_conn_stats);
 | 
				
			||||||
 | 
							ratectr->all_osmux_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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by On-Waves
 | 
				
			||||||
 | 
					 * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/osmo_io.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_rtp_end.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***********************
 | 
				
			||||||
 | 
					 * mgcp_rtp_end
 | 
				
			||||||
 | 
					 **********************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk;
 | 
				
			||||||
 | 
						struct mgcp_config *cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end->conn_rtp = conn_rtp;
 | 
				
			||||||
 | 
						end->rtp = NULL;
 | 
				
			||||||
 | 
						end->rtcp = NULL;
 | 
				
			||||||
 | 
						memset(&end->addr, 0, sizeof(end->addr));
 | 
				
			||||||
 | 
						end->rtcp_port = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set default values */
 | 
				
			||||||
 | 
						end->frames_per_packet = 0;	/* unknown */
 | 
				
			||||||
 | 
						end->output_enabled = false;
 | 
				
			||||||
 | 
						end->maximum_packet_time = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						end->force_aligned_timing = trunk->force_aligned_timing;
 | 
				
			||||||
 | 
						end->force_constant_ssrc = trunk->force_constant_ssrc;
 | 
				
			||||||
 | 
						end->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cfg->force_ptime) {
 | 
				
			||||||
 | 
							end->packet_duration_ms = cfg->force_ptime;
 | 
				
			||||||
 | 
							end->force_output_ptime = 1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&end->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mgcp_rtp_end_free_port(end);
 | 
				
			||||||
 | 
						mgcp_codecset_reset(&end->cset);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (end->force_output_ptime)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						end->packet_duration_ms = packet_duration_ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
				
			||||||
 | 
						       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! free allocated RTP and RTCP ports.
 | 
				
			||||||
 | 
					 *  \param[in] end RTP end */
 | 
				
			||||||
 | 
					void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (end->rtp) {
 | 
				
			||||||
 | 
							osmo_iofd_free(end->rtp);
 | 
				
			||||||
 | 
							end->rtp = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (end->rtcp) {
 | 
				
			||||||
 | 
							osmo_iofd_free(end->rtcp);
 | 
				
			||||||
 | 
							end->rtcp = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -239,13 +239,12 @@ static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp
 | 
				
			|||||||
		if (delimiter == ';' || delimiter == ',')
 | 
							if (delimiter == ';' || delimiter == ',')
 | 
				
			||||||
			str_ptr[strlen(str_ptr) - 1] = '\0';
 | 
								str_ptr[strlen(str_ptr) - 1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* AMR octet aligned parameter */
 | 
							/* AMR octet aligned parameter (see also RFC 3267, section 8.3) */
 | 
				
			||||||
		if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
 | 
							if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
 | 
				
			||||||
			fmtp_param->param.amr_octet_aligned_present = true;
 | 
								fmtp_param->param.amr_octet_aligned_present = true;
 | 
				
			||||||
			fmtp_param->param.amr_octet_aligned = false;
 | 
								fmtp_param->param.amr_octet_aligned = false;
 | 
				
			||||||
			if (amr_octet_aligned == 1)
 | 
								if (amr_octet_aligned == 1)
 | 
				
			||||||
				fmtp_param->param.amr_octet_aligned = true;
 | 
									fmtp_param->param.amr_octet_aligned = true;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		param_str = strtok(NULL, " ");
 | 
							param_str = strtok(NULL, " ");
 | 
				
			||||||
@@ -313,16 +312,13 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze SDP input string.
 | 
					/*! Analyze SDP input string.
 | 
				
			||||||
 *  \param[in] endp trunk endpoint.
 | 
					 *  \param[inout] p provided memory to store the parsing results.
 | 
				
			||||||
 *  \param[out] conn associated rtp connection.
 | 
					 | 
				
			||||||
 *  \param[out] caller provided memory to store the parsing results.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Note: In conn (conn->end) the function returns the packet duration,
 | 
					 | 
				
			||||||
 *  rtp port, rtcp port and the codec information.
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -1 on failure. */
 | 
					 *  \returns 0 on success, -1 on failure. */
 | 
				
			||||||
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
					int mgcp_parse_sdp_data(struct mgcp_parse_data *p)
 | 
				
			||||||
			struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(p);
 | 
				
			||||||
 | 
						struct mgcp_parse_sdp *sdp = &p->sdp;
 | 
				
			||||||
	struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
						struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int codecs_used = 0;
 | 
						unsigned int codecs_used = 0;
 | 
				
			||||||
	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
						struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
				
			||||||
@@ -332,19 +328,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int payload;
 | 
						int payload_type;
 | 
				
			||||||
	int ptime, ptime2 = 0;
 | 
						int ptime, ptime2 = 0;
 | 
				
			||||||
	char audio_name[64];
 | 
						char audio_name[64];
 | 
				
			||||||
	int port, rc;
 | 
						int port, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtp = &conn->end;
 | 
					 | 
				
			||||||
	memset(&codecs, 0, sizeof(codecs));
 | 
						memset(&codecs, 0, sizeof(codecs));
 | 
				
			||||||
 | 
						mgcp_parse_sdp_init(sdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (line[0]) {
 | 
				
			||||||
@@ -355,26 +346,26 @@ 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;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
								if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
				
			||||||
				if (ptime2 > 0 && ptime2 != ptime)
 | 
									if (ptime2 > 0 && ptime2 != ptime)
 | 
				
			||||||
					rtp->packet_duration_ms = 0;
 | 
										sdp->ptime = 0;
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					rtp->packet_duration_ms = ptime;
 | 
										sdp->ptime = ptime;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
								if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
				
			||||||
				rtp->maximum_packet_time = ptime2;
 | 
									sdp->maxptime = ptime2;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
								if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
				
			||||||
				rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
 | 
									rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line);
 | 
				
			||||||
				if (rc >= 0)
 | 
									if (rc >= 0)
 | 
				
			||||||
					fmtp_used++;
 | 
										fmtp_used++;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
@@ -383,31 +374,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'm':
 | 
							case 'm':
 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
				
			||||||
			if (rc == 1) {
 | 
								if (rc == 1)
 | 
				
			||||||
				rtp->rtp_port = htons(port);
 | 
									sdp->rtp_port = port;
 | 
				
			||||||
				rtp->rtcp_port = htons(port + 1);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			rc = pt_from_sdp(conn->conn, codecs,
 | 
								rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line);
 | 
				
			||||||
					 ARRAY_SIZE(codecs), line);
 | 
					 | 
				
			||||||
			if (rc > 0)
 | 
								if (rc > 0)
 | 
				
			||||||
				codecs_used = rc;
 | 
									codecs_used = rc;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'c':
 | 
							case 'c':
 | 
				
			||||||
			if (audio_ip_from_sdp(&rtp->addr, line) < 0)
 | 
								if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) {
 | 
				
			||||||
 | 
									talloc_free(tmp_ctx);
 | 
				
			||||||
				return -1;
 | 
									return -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if (p->endp)
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
				/* TODO: Check spec: We used the bare endpoint number before,
 | 
								     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
				
			||||||
				 * now we use the endpoint name as a whole? Is this allowed? */
 | 
								     line[0], line[0], p->epname);
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
					 | 
				
			||||||
				     line[0], line[0], endp->name);
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d\n",
 | 
					 | 
				
			||||||
				     line[0], line[0]);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -421,23 +404,22 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	/* Store parsed codec information */
 | 
						/* Store parsed codec information */
 | 
				
			||||||
	for (i = 0; i < codecs_used; i++) {
 | 
						for (i = 0; i < codecs_used; i++) {
 | 
				
			||||||
		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
							codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
				
			||||||
		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
							rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
 | 
								LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(tmp_ctx);
 | 
						talloc_free(tmp_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
						     "%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
				
			||||||
	     ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
						     p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime);
 | 
				
			||||||
	     rtp->packet_duration_ms);
 | 
					 | 
				
			||||||
	if (codecs_used == 0)
 | 
						if (codecs_used == 0)
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
				
			||||||
	for (i = 0; i < codecs_used; i++) {
 | 
						for (i = 0; i < codecs_used; i++) {
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
 | 
				
			||||||
		      rtp->codecs[i].payload_type,
 | 
							      sdp->cset.codecs[i].payload_type,
 | 
				
			||||||
		      rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
 | 
							      strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown");
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, " ");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
						LOGPC(DLMGCP, LOGL_NOTICE, "\n");
 | 
				
			||||||
@@ -487,34 +469,10 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Add fmtp strings to sdp payload */
 | 
					/* Add fmtp strings to sdp payload */
 | 
				
			||||||
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
 | 
					static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
 | 
				
			||||||
		    const char *fmtp_extra)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	int fmtp_extra_pt = -1;
 | 
					 | 
				
			||||||
	char *fmtp_extra_pars = "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When no fmtp parameters ara available but an fmtp extra string
 | 
					 | 
				
			||||||
	 * is configured, just add the fmtp extra string */
 | 
					 | 
				
			||||||
	if (fmtp_params_len == 0 && fmtp_extra) {
 | 
					 | 
				
			||||||
		return msgb_printf(sdp, "%s\r\n", fmtp_extra);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When there is fmtp extra configured we dissect it in order to drop
 | 
					 | 
				
			||||||
	 * in the configured extra parameters at the right place when
 | 
					 | 
				
			||||||
	 * generating the fmtp strings. */
 | 
					 | 
				
			||||||
	if (fmtp_extra) {
 | 
					 | 
				
			||||||
		if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
 | 
					 | 
				
			||||||
			fmtp_extra_pt = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		fmtp_extra_pars = strstr(fmtp_extra, " ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!fmtp_extra_pars)
 | 
					 | 
				
			||||||
			fmtp_extra_pars = "";
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			fmtp_extra_pars++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < fmtp_params_len; i++) {
 | 
						for (i = 0; i < fmtp_params_len; i++) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
							rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
				
			||||||
@@ -531,13 +489,6 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
 | 
				
			|||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Append extra parameters from fmtp extra */
 | 
					 | 
				
			||||||
		if (fmtp_params[i].payload_type == fmtp_extra_pt) {
 | 
					 | 
				
			||||||
			rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
 | 
					 | 
				
			||||||
			if (rc < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rc = msgb_printf(sdp, "\r\n");
 | 
							rc = msgb_printf(sdp, "\r\n");
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
@@ -557,7 +508,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			    const char *addr)
 | 
								    const char *addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct mgcp_rtp_codec *codec;
 | 
						const struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	const char *fmtp_extra;
 | 
					 | 
				
			||||||
	const char *audio_name;
 | 
						const char *audio_name;
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	struct sdp_fmtp_param fmtp_param;
 | 
						struct sdp_fmtp_param fmtp_param;
 | 
				
			||||||
@@ -573,10 +523,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	OSMO_ASSERT(sdp);
 | 
						OSMO_ASSERT(sdp);
 | 
				
			||||||
	OSMO_ASSERT(addr);
 | 
						OSMO_ASSERT(addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
						codec = conn->end.cset.codec;
 | 
				
			||||||
	endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
					 | 
				
			||||||
					      &codec, &fmtp_extra,
 | 
					 | 
				
			||||||
					      (struct mgcp_conn_rtp *)conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_name = codec->audio_name;
 | 
						audio_name = codec->audio_name;
 | 
				
			||||||
	payload_type = codec->payload_type;
 | 
						payload_type = codec->payload_type;
 | 
				
			||||||
@@ -599,7 +546,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.local_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);
 | 
				
			||||||
@@ -618,7 +565,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			fmtp_params[0] = fmtp_param;
 | 
								fmtp_params[0] = fmtp_param;
 | 
				
			||||||
			fmtp_params_len = 1;
 | 
								fmtp_params_len = 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
 | 
							rc = add_fmtp(sdp, fmtp_params, fmtp_params_len);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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->ctrg, 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->ctrg, 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->ctrg, 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->ctrg, 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->ctrg, 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.usage != 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,
 | 
				
			||||||
@@ -106,9 +112,12 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
		str_len -= nchars;
 | 
							str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
							if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
				
			||||||
 | 
								struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
 | 
				
			||||||
 | 
								osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
				
			||||||
 | 
								osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
 | 
				
			||||||
			snprintf(str, str_len,
 | 
								snprintf(str, str_len,
 | 
				
			||||||
				 "\r\nX-Osmux-ST: CR=%u, BR=%u",
 | 
									 "\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
 | 
				
			||||||
				 conn->osmux.stats.chunks, conn->osmux.stats.octets);
 | 
									 osmux_chunks_rx->current, osmux_octets_rx->current);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
 | 
				
			|||||||
	 * keep this option open: */
 | 
						 * keep this option open: */
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
 | 
							mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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
 | 
				
			||||||
@@ -253,3 +306,43 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Try to find a free port by attempting to bind on it. Also handle the
 | 
				
			||||||
 | 
					 * counter that points on the next free port. Since we have a pointer
 | 
				
			||||||
 | 
					 * to the next free port, binding should in work on the first attempt in
 | 
				
			||||||
 | 
					 * general. In case of failure the next port is tried until the whole port
 | 
				
			||||||
 | 
					 * range is tried once. */
 | 
				
			||||||
 | 
					int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct mgcp_port_range *range;
 | 
				
			||||||
 | 
						unsigned int tries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						range = &trunk->cfg->net_ports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pthread_mutex_lock(&range->lock);
 | 
				
			||||||
 | 
						/* attempt to find a port */
 | 
				
			||||||
 | 
						tries = (range->range_end - range->range_start) / 2;
 | 
				
			||||||
 | 
						for (i = 0; i < tries; ++i) {
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (range->last_port >= range->range_end)
 | 
				
			||||||
 | 
								range->last_port = range->range_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							range->last_port += 2;
 | 
				
			||||||
 | 
							if (rc == 0) {
 | 
				
			||||||
 | 
								pthread_mutex_unlock(&range->lock);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&range->lock);
 | 
				
			||||||
 | 
						LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							 "Allocating a RTP/RTCP port failed %u times.\n", tries);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
@@ -111,25 +111,20 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
 | 
							vty_out(vty, " no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
	if (trunk->audio_fmtp_extra)
 | 
					 | 
				
			||||||
		vty_out(vty, " sdp audio fmtp-extra %s%s",
 | 
					 | 
				
			||||||
			trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
					 | 
				
			||||||
	vty_out(vty, " %ssdp audio-payload send-ptime%s",
 | 
						vty_out(vty, " %ssdp audio-payload send-ptime%s",
 | 
				
			||||||
		trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 | 
							trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " %ssdp audio-payload send-name%s",
 | 
						vty_out(vty, " %ssdp audio-payload send-name%s",
 | 
				
			||||||
		trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
 | 
							trunk->audio_send_name ? "" : "no ", VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " number endpoints %u%s",
 | 
						vty_out(vty, " number endpoints %u%s",
 | 
				
			||||||
		trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
							trunk->v.vty_number_endpoints, VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, " %sallow-transcoding%s",
 | 
						if (strlen(g_cfg->call_agent_addr))
 | 
				
			||||||
		trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	if (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)
 | 
				
			||||||
		vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
							vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (g_cfg->osmux) {
 | 
						switch (g_cfg->osmux.usage) {
 | 
				
			||||||
	case OSMUX_USAGE_ON:
 | 
						case OSMUX_USAGE_ON:
 | 
				
			||||||
		vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -141,17 +136,23 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (g_cfg->osmux) {
 | 
						if (g_cfg->osmux.usage != OSMUX_USAGE_OFF) {
 | 
				
			||||||
		vty_out(vty, " osmux bind-ip %s%s",
 | 
							if (g_cfg->osmux.local_addr_v4)
 | 
				
			||||||
			g_cfg->osmux_addr, VTY_NEWLINE);
 | 
								vty_out(vty, " osmux bind-ip %s%s",
 | 
				
			||||||
 | 
									g_cfg->osmux.local_addr_v4, VTY_NEWLINE);
 | 
				
			||||||
 | 
							if (g_cfg->osmux.local_addr_v6)
 | 
				
			||||||
 | 
								vty_out(vty, " osmux bind-ip-v6 %s%s",
 | 
				
			||||||
 | 
									g_cfg->osmux.local_addr_v6, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux batch-factor %d%s",
 | 
							vty_out(vty, " osmux batch-factor %d%s",
 | 
				
			||||||
			g_cfg->osmux_batch, VTY_NEWLINE);
 | 
								g_cfg->osmux.batch_factor, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux batch-size %u%s",
 | 
							vty_out(vty, " osmux batch-size %u%s",
 | 
				
			||||||
			g_cfg->osmux_batch_size, VTY_NEWLINE);
 | 
								g_cfg->osmux.batch_size, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux port %u%s",
 | 
							vty_out(vty, " osmux port %u%s",
 | 
				
			||||||
			g_cfg->osmux_port, VTY_NEWLINE);
 | 
								g_cfg->osmux.local_port, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux dummy %s%s",
 | 
							vty_out(vty, " osmux dummy %s%s",
 | 
				
			||||||
			g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
 | 
								g_cfg->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, " osmux peer-behind-nat %s%s",
 | 
				
			||||||
 | 
								g_cfg->osmux.peer_behind_nat ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->conn_timeout)
 | 
						if (g_cfg->conn_timeout)
 | 
				
			||||||
@@ -164,16 +165,16 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
						struct mgcp_rtp_state *state = &conn->state;
 | 
				
			||||||
	struct mgcp_rtp_end *end = &conn->end;
 | 
						struct mgcp_rtp_end *end = &conn->end;
 | 
				
			||||||
	struct mgcp_rtp_codec *codec = end->codec;
 | 
						struct mgcp_rtp_codec *codec = end->cset.codec;
 | 
				
			||||||
	struct rate_ctr *tx_packets, *tx_bytes;
 | 
						struct rate_ctr *tx_packets, *tx_bytes;
 | 
				
			||||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
						struct rate_ctr *rx_packets, *rx_bytes;
 | 
				
			||||||
	struct rate_ctr *dropped_packets;
 | 
						struct rate_ctr *dropped_packets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tx_packets = &conn->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR];
 | 
						tx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	tx_bytes = &conn->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR];
 | 
						tx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
	rx_packets = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
 | 
						rx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	rx_bytes = &conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR];
 | 
						rx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	dropped_packets = &conn->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR];
 | 
						dropped_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_DROPPED_PACKETS_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty,
 | 
						vty_out(vty,
 | 
				
			||||||
		"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
							"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
@@ -183,28 +184,52 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		"   Payload Type: %d Rate: %u Channels: %d %s"
 | 
							"   Payload Type: %d Rate: %u Channels: %d %s"
 | 
				
			||||||
		"   Frame Duration: %u Frame Denominator: %u%s"
 | 
							"   Frame Duration: %u Frame Denominator: %u%s"
 | 
				
			||||||
		"   FPP: %d Packet Duration: %u%s"
 | 
							"   FPP: %d Packet Duration: %u%s"
 | 
				
			||||||
		"   FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
 | 
							"   Audio-Name: %s Sub-Type: %s%s"
 | 
				
			||||||
		"   Output-Enabled: %d Force-PTIME: %d%s",
 | 
							"   Output-Enabled: %d Force-PTIME: %d%s",
 | 
				
			||||||
		tx_packets->current, tx_bytes->current, VTY_NEWLINE,
 | 
							tx_packets->current, tx_bytes->current, VTY_NEWLINE,
 | 
				
			||||||
		rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
							rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
				
			||||||
		state->in_stream.err_ts_ctr->current,
 | 
							state->in_stream.err_ts_ctr->current,
 | 
				
			||||||
		state->out_stream.err_ts_ctr->current,
 | 
							state->out_stream.err_ts_ctr->current,
 | 
				
			||||||
	        VTY_NEWLINE,
 | 
							VTY_NEWLINE,
 | 
				
			||||||
		dropped_packets->current, VTY_NEWLINE,
 | 
							dropped_packets->current, VTY_NEWLINE,
 | 
				
			||||||
		codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
							codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
				
			||||||
		codec->frame_duration_num, codec->frame_duration_den,
 | 
							codec->frame_duration_num, codec->frame_duration_den,
 | 
				
			||||||
		VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
 | 
							VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms,
 | 
				
			||||||
		VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
							VTY_NEWLINE, codec->audio_name,
 | 
				
			||||||
		codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
							codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
				
			||||||
		end->force_output_ptime, VTY_NEWLINE);
 | 
							end->force_output_ptime, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
 | 
							struct rate_ctr *rx_chunks, *rx_octets, *rtp_tx, *rtp_tx_dropped, *octets_tx;
 | 
				
			||||||
 | 
							rx_chunks = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
				
			||||||
 | 
							rx_octets = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_OCTETS_RX_CTR);
 | 
				
			||||||
 | 
							rtp_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_CTR);
 | 
				
			||||||
 | 
							rtp_tx_dropped =  rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
				
			||||||
 | 
							octets_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_AMR_OCTETS_TX_CTR);
 | 
				
			||||||
 | 
							vty_out(vty,
 | 
				
			||||||
 | 
							"   Osmux:%s"
 | 
				
			||||||
 | 
							"    State: %s%s"
 | 
				
			||||||
 | 
							"    Local CID: %d%s"
 | 
				
			||||||
 | 
							"    Remote CID: %d%s"
 | 
				
			||||||
 | 
							"    Chunks received: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
 | 
							"    RTP Packets encoded (Tx): %" PRIu64 " (%" PRIu64 " AMR octets total)%s"
 | 
				
			||||||
 | 
							"    AMR payloads Dropped (Tx): %" PRIu64 "%s",
 | 
				
			||||||
 | 
							VTY_NEWLINE, osmux_state_str(conn->osmux.state), VTY_NEWLINE,
 | 
				
			||||||
 | 
							conn->osmux.local_cid_allocated ? conn->osmux.local_cid : -1, VTY_NEWLINE,
 | 
				
			||||||
 | 
							conn->osmux.remote_cid_present ? conn->osmux.remote_cid : -1, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rx_chunks->current, rx_octets->current, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rtp_tx->current, octets_tx->current, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rtp_tx_dropped->current, VTY_NEWLINE
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
@@ -218,7 +243,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",
 | 
				
			||||||
@@ -229,7 +254,8 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			|||||||
			 * connection types (E1) as soon as
 | 
								 * connection types (E1) as soon as
 | 
				
			||||||
			 * the implementation is available */
 | 
								 * the implementation is available */
 | 
				
			||||||
			if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
								if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
				dump_rtp_end(vty, &conn->u.rtp);
 | 
									struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
 | 
									dump_rtp_end(vty, conn_rtp);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -289,6 +315,14 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
 | 
				
			|||||||
					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
										   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
				
			||||||
					   ratectr->all_rtp_conn_stats);
 | 
										   ratectr->all_rtp_conn_stats);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_osmux_conn_stats) {
 | 
				
			||||||
 | 
							vty_out(vty, "   %s:%s",
 | 
				
			||||||
 | 
								ratectr->all_osmux_conn_stats->desc->group_description,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out_rate_ctr_group_fmt(vty,
 | 
				
			||||||
 | 
										   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
				
			||||||
 | 
										   ratectr->all_osmux_conn_stats);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
						if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
				
			||||||
		vty_out(vty, "   %s:%s",
 | 
							vty_out(vty, "   %s:%s",
 | 
				
			||||||
@@ -301,9 +335,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",
 | 
				
			||||||
@@ -316,31 +351,32 @@ 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.usage != OSMUX_USAGE_OFF)
 | 
				
			||||||
		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(),
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -350,6 +386,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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -359,7 +416,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 {
 | 
				
			||||||
@@ -420,7 +477,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -432,7 +489,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -452,6 +509,7 @@ DEFUN_DEPRECATED(cfg_mgcp_bind_early,
 | 
				
			|||||||
		 BIND_STR
 | 
							 BIND_STR
 | 
				
			||||||
		 "Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
 | 
							 "Bind local ports on start up\n" "Bind on demand\n" "Bind on startup\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'bind early (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -510,7 +568,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,
 | 
				
			||||||
@@ -525,8 +583,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,
 | 
				
			||||||
@@ -542,7 +599,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -553,8 +610,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -623,53 +679,40 @@ DEFUN_USRATTR(cfg_mgcp_no_rtp_force_ptime,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_mgcp_sdp_fmtp_extra,
 | 
					 | 
				
			||||||
	      cfg_mgcp_sdp_fmtp_extra_cmd,
 | 
					 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "sdp audio fmtp-extra .NAME",
 | 
					 | 
				
			||||||
	      "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
 | 
					 | 
				
			||||||
	      "Extra Information\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
					 | 
				
			||||||
	char *txt = argv_concat(argv, argc, 0);
 | 
					 | 
				
			||||||
	if (!txt)
 | 
					 | 
				
			||||||
		return CMD_WARNING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
 | 
					 | 
				
			||||||
	talloc_free(txt);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN_USRATTR(cfg_mgcp_allow_transcoding,
 | 
					 | 
				
			||||||
	      cfg_mgcp_allow_transcoding_cmd,
 | 
					 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "allow-transcoding", "Allow transcoding\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
					 | 
				
			||||||
	trunk->no_audio_transcoding = 0;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN_USRATTR(cfg_mgcp_no_allow_transcoding,
 | 
					 | 
				
			||||||
	      cfg_mgcp_no_allow_transcoding_cmd,
 | 
					 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
					 | 
				
			||||||
	trunk->no_audio_transcoding = 1;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SDP_STR "SDP File related options\n"
 | 
					#define SDP_STR "SDP File related options\n"
 | 
				
			||||||
#define AUDIO_STR "Audio payload options\n"
 | 
					#define AUDIO_STR "Audio payload options\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_DEPRECATED(cfg_mgcp_sdp_fmtp_extra,
 | 
				
			||||||
 | 
						      cfg_mgcp_sdp_fmtp_extra_cmd,
 | 
				
			||||||
 | 
						      "sdp audio fmtp-extra .NAME",
 | 
				
			||||||
 | 
						      SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_DEPRECATED(cfg_mgcp_allow_transcoding,
 | 
				
			||||||
 | 
							  cfg_mgcp_allow_transcoding_cmd,
 | 
				
			||||||
 | 
							  "allow-transcoding", "Allow transcoding\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN_DEPRECATED(cfg_mgcp_no_allow_transcoding,
 | 
				
			||||||
 | 
							 cfg_mgcp_no_allow_transcoding_cmd,
 | 
				
			||||||
 | 
							 "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
 | 
					DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_number,
 | 
				
			||||||
      cfg_mgcp_sdp_payload_number_cmd,
 | 
					      cfg_mgcp_sdp_payload_number_cmd,
 | 
				
			||||||
      "sdp audio-payload number <0-255>",
 | 
					      "sdp audio-payload number <0-255>",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Number\n" "Payload number\n")
 | 
					      SDP_STR AUDIO_STR "Number\n" "Payload number\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -683,6 +726,7 @@ DEFUN_DEPRECATED(cfg_mgcp_sdp_payload_name,
 | 
				
			|||||||
      "sdp audio-payload name NAME",
 | 
					      "sdp audio-payload name NAME",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Name\n" "Payload name\n")
 | 
					      SDP_STR AUDIO_STR "Name\n" "Payload name\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -743,6 +787,7 @@ DEFUN_DEPRECATED(cfg_mgcp_loop,
 | 
				
			|||||||
		 "loop (0|1)",
 | 
							 "loop (0|1)",
 | 
				
			||||||
		 "Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
 | 
							 "Loop audio for all endpoints on main trunk\n" "Don't Loop\n" "Loop\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -812,7 +857,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 1;
 | 
						trunk->force_constant_ssrc = true;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -823,7 +868,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -878,7 +923,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	trunk->force_aligned_timing = 0;
 | 
						trunk->force_aligned_timing = 0;
 | 
				
			||||||
	trunk->rfc5993_hr_convert = false;
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -927,7 +972,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -940,7 +985,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) {
 | 
				
			||||||
@@ -972,7 +1017,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);
 | 
				
			||||||
@@ -1007,30 +1052,17 @@ static int config_write_trunk(struct vty *vty)
 | 
				
			|||||||
				VTY_NEWLINE);
 | 
									VTY_NEWLINE);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
								vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
		if (trunk->audio_fmtp_extra)
 | 
					 | 
				
			||||||
			vty_out(vty, "   sdp audio fmtp-extra %s%s",
 | 
					 | 
				
			||||||
				trunk->audio_fmtp_extra, VTY_NEWLINE);
 | 
					 | 
				
			||||||
		vty_out(vty, "  %sallow-transcoding%s",
 | 
					 | 
				
			||||||
			trunk->no_audio_transcoding ? "no " : "", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_trunk_sdp_fmtp_extra,
 | 
					DEFUN_DEPRECATED(cfg_trunk_sdp_fmtp_extra,
 | 
				
			||||||
	      cfg_trunk_sdp_fmtp_extra_cmd,
 | 
						      cfg_trunk_sdp_fmtp_extra_cmd,
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
					 | 
				
			||||||
	      "sdp audio fmtp-extra .NAME",
 | 
						      "sdp audio fmtp-extra .NAME",
 | 
				
			||||||
	      "Add extra fmtp for the SDP file\n" "Audio\n" "Fmtp-extra\n"
 | 
						      SDP_STR AUDIO_STR "Deprecated, without effect since osmo-mgw v1.13\n" "Deprecated, without effect\n")
 | 
				
			||||||
	      "Extra Information\n")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						vty_out(vty, "%% deprecated: the config option 'sdp audio fmtp-extra' has been removed.%s", VTY_NEWLINE);
 | 
				
			||||||
	char *txt = argv_concat(argv, argc, 0);
 | 
					 | 
				
			||||||
	if (!txt)
 | 
					 | 
				
			||||||
		return CMD_WARNING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &trunk->audio_fmtp_extra, txt);
 | 
					 | 
				
			||||||
	talloc_free(txt);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1039,6 +1071,7 @@ DEFUN_DEPRECATED(cfg_trunk_payload_number,
 | 
				
			|||||||
      "sdp audio-payload number <0-255>",
 | 
					      "sdp audio-payload number <0-255>",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
 | 
					      SDP_STR AUDIO_STR "Number\n" "Payload Number\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'sdp audio-payload number <0-255>' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1051,6 +1084,7 @@ DEFUN_DEPRECATED(cfg_trunk_payload_name,
 | 
				
			|||||||
      "sdp audio-payload name NAME",
 | 
					      "sdp audio-payload name NAME",
 | 
				
			||||||
      SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
 | 
					      SDP_STR AUDIO_STR "Payload\n" "Payload Name\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'sdp audio-payload name NAME' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1063,6 +1097,7 @@ DEFUN_DEPRECATED(cfg_trunk_loop,
 | 
				
			|||||||
		 "loop (0|1)",
 | 
							 "loop (0|1)",
 | 
				
			||||||
		 "Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
 | 
							 "Loop audio for all endpoints on this trunk\n" "Don't Loop\n" "Loop\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						vty_out(vty, "%% Deprecated 'loop (0|1)' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1162,7 +1197,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc,
 | 
				
			|||||||
	      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
						      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 1;
 | 
						trunk->force_constant_ssrc = true;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1172,7 +1207,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc,
 | 
				
			|||||||
	      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
						      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1222,7 +1257,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp,
 | 
				
			|||||||
	      "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
						      "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						struct mgcp_trunk *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = false;
 | 
				
			||||||
	trunk->force_aligned_timing = 0;
 | 
						trunk->force_aligned_timing = 0;
 | 
				
			||||||
	trunk->rfc5993_hr_convert = false;
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -1260,23 +1295,19 @@ DEFUN_ATTR(cfg_trunk_no_rtp_keepalive,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_trunk_allow_transcoding,
 | 
					DEFUN_DEPRECATED(cfg_trunk_allow_transcoding,
 | 
				
			||||||
	      cfg_trunk_allow_transcoding_cmd,
 | 
							 cfg_trunk_allow_transcoding_cmd,
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
							 "allow-transcoding", "Allow transcoding\n")
 | 
				
			||||||
	      "allow-transcoding", "Allow transcoding\n")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						vty_out(vty, "%% Deprecated 'allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	trunk->no_audio_transcoding = 0;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_USRATTR(cfg_trunk_no_allow_transcoding,
 | 
					DEFUN_DEPRECATED(cfg_trunk_no_allow_transcoding,
 | 
				
			||||||
	      cfg_trunk_no_allow_transcoding_cmd,
 | 
							 cfg_trunk_no_allow_transcoding_cmd,
 | 
				
			||||||
	      X(MGW_CMD_ATTR_NEWCONN),
 | 
							 "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
				
			||||||
	      "no allow-transcoding", NO_STR "Allow transcoding\n")
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk *trunk = vty->index;
 | 
						vty_out(vty, "%% Deprecated 'no allow-transcoding' config no longer has any effect%s", VTY_NEWLINE);
 | 
				
			||||||
	trunk->no_audio_transcoding = 1;
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1312,7 +1343,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1327,10 +1358,11 @@ DEFUN(loop_conn,
 | 
				
			|||||||
	endp = trunk->endpoints[endp_no];
 | 
						endp = trunk->endpoints[endp_no];
 | 
				
			||||||
	int loop = atoi(argv[2]);
 | 
						int loop = atoi(argv[2]);
 | 
				
			||||||
	llist_for_each_entry(conn, &endp->conns, entry) {
 | 
						llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
		if (conn->type == MGCP_CONN_TYPE_RTP)
 | 
							if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
			/* Handle it like a MDCX, switch on SSRC patching if enabled */
 | 
								/* Handle it like a MDCX, switch on SSRC patching if enabled */
 | 
				
			||||||
			mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end);
 | 
								struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn);
 | 
				
			||||||
		else {
 | 
								conn_rtp->state.patch.patch_ssrc = true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			/* FIXME: Introduce support for other connection (E1)
 | 
								/* FIXME: Introduce support for other connection (E1)
 | 
				
			||||||
			 * types when implementation is available */
 | 
								 * types when implementation is available */
 | 
				
			||||||
			vty_out(vty, "%%Can't enable SSRC patching,"
 | 
								vty_out(vty, "%%Can't enable SSRC patching,"
 | 
				
			||||||
@@ -1373,7 +1405,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1388,7 +1420,7 @@ DEFUN(tap_rtp,
 | 
				
			|||||||
	endp = trunk->endpoints[endp_no];
 | 
						endp = trunk->endpoints[endp_no];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_id = argv[2];
 | 
						conn_id = argv[2];
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_endp_get_conn_rtp(endp, conn_id);
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn) {
 | 
				
			||||||
		vty_out(vty, "Conn ID %s is invalid.%s",
 | 
							vty_out(vty, "Conn ID %s is invalid.%s",
 | 
				
			||||||
			conn_id, VTY_NEWLINE);
 | 
								conn_id, VTY_NEWLINE);
 | 
				
			||||||
@@ -1440,7 +1472,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1473,7 +1505,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1518,12 +1550,12 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(argv[0], "off") == 0) {
 | 
						if (strcmp(argv[0], "off") == 0) {
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_OFF;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_OFF;
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	} else if (strcmp(argv[0], "on") == 0)
 | 
						} else if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_ON;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_ON;
 | 
				
			||||||
	else if (strcmp(argv[0], "only") == 0)
 | 
						else if (strcmp(argv[0], "only") == 0)
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_ONLY;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1531,12 +1563,29 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_ip,
 | 
					DEFUN(cfg_mgcp_osmux_ip,
 | 
				
			||||||
      cfg_mgcp_osmux_ip_cmd,
 | 
					      cfg_mgcp_osmux_ip_cmd,
 | 
				
			||||||
      "osmux bind-ip " VTY_IPV46_CMD,
 | 
					      "osmux bind-ip " VTY_IPV4_CMD,
 | 
				
			||||||
 | 
					      OSMUX_STR IP_STR
 | 
				
			||||||
 | 
					      "IPv4 Address to bind to\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v4, argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_ip_v6,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_ip_v6_cmd,
 | 
				
			||||||
 | 
					      "osmux bind-ip-v6 " VTY_IPV6_CMD,
 | 
				
			||||||
      OSMUX_STR IP_STR
 | 
					      OSMUX_STR IP_STR
 | 
				
			||||||
      "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_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v6, argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_port,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_port_cmd,
 | 
				
			||||||
 | 
					      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->osmux.local_port = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1545,7 +1594,7 @@ DEFUN(cfg_mgcp_osmux_batch_factor,
 | 
				
			|||||||
      "osmux batch-factor <1-8>",
 | 
					      "osmux batch-factor <1-8>",
 | 
				
			||||||
      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
					      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux_batch = atoi(argv[0]);
 | 
						g_cfg->osmux.batch_factor = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1554,15 +1603,7 @@ DEFUN(cfg_mgcp_osmux_batch_size,
 | 
				
			|||||||
      "osmux batch-size <1-65535>",
 | 
					      "osmux batch-size <1-65535>",
 | 
				
			||||||
      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
					      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux_batch_size = atoi(argv[0]);
 | 
						g_cfg->osmux.batch_size = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_port,
 | 
					 | 
				
			||||||
      cfg_mgcp_osmux_port_cmd,
 | 
					 | 
				
			||||||
      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	g_cfg->osmux_port = atoi(argv[0]);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1573,9 +1614,24 @@ DEFUN(cfg_mgcp_osmux_dummy,
 | 
				
			|||||||
      "Disable dummy padding\n")
 | 
					      "Disable dummy padding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(argv[0], "on") == 0)
 | 
						if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux_dummy = 1;
 | 
							g_cfg->osmux.dummy_padding = true;
 | 
				
			||||||
	else if (strcmp(argv[0], "off") == 0)
 | 
						else if (strcmp(argv[0], "off") == 0)
 | 
				
			||||||
		g_cfg->osmux_dummy = 0;
 | 
							g_cfg->osmux.dummy_padding = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_peer_behind_nat,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_peer_behind_nat_cmd,
 | 
				
			||||||
 | 
					      "osmux peer-behind-nat (on|off)",
 | 
				
			||||||
 | 
					      OSMUX_STR "Define whether peer is behind NAT\n"
 | 
				
			||||||
 | 
					      "Peer is behind NAT\n"
 | 
				
			||||||
 | 
					      "Peer is NOT behind NAT\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
 | 
							g_cfg->osmux.peer_behind_nat = true;
 | 
				
			||||||
 | 
						else if (strcmp(argv[0], "off") == 0)
 | 
				
			||||||
 | 
							g_cfg->osmux.peer_behind_nat = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1606,6 +1662,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);
 | 
				
			||||||
@@ -1664,10 +1721,12 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
					 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_peer_behind_nat_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
				
			||||||
@@ -1712,9 +1771,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->osmux_port = OSMUX_PORT;
 | 
						cfg->osmux.local_port = OSMUX_DEFAULT_PORT;
 | 
				
			||||||
	cfg->osmux_batch = 4;
 | 
						cfg->osmux.batch_factor = 4;
 | 
				
			||||||
	cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
						cfg->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_cfg = cfg;
 | 
						g_cfg = cfg;
 | 
				
			||||||
	rc = vty_read_config_file(config_file, NULL);
 | 
						rc = vty_read_config_file(config_file, NULL);
 | 
				
			||||||
@@ -1724,7 +1783,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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1732,7 +1791,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;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,6 @@
 | 
				
			|||||||
#include <osmocom/mgcp/debug.h>
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_ctrl.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
@@ -51,7 +50,7 @@
 | 
				
			|||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
#include <osmocom/ctrl/control_vty.h>
 | 
					#include <osmocom/ctrl/control_vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/telnet_interface.h>
 | 
					#include <osmocom/vty/telnet_interface.h>
 | 
				
			||||||
@@ -83,7 +82,7 @@ static int daemonize = 0;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const char *osmomgw_copyright =
 | 
					const char *osmomgw_copyright =
 | 
				
			||||||
	"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
 | 
						"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
 | 
				
			||||||
	"Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
 | 
						"Copyright (C) 2017-2022 by sysmocom s.f.m.c. GmbH\r\n"
 | 
				
			||||||
	"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
 | 
						"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
 | 
				
			||||||
	"Philipp Maier\r\n\r\n"
 | 
						"Philipp Maier\r\n\r\n"
 | 
				
			||||||
	"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
 | 
						"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
 | 
				
			||||||
@@ -95,7 +94,7 @@ static char *config_file = "osmo-mgw.cfg";
 | 
				
			|||||||
/* used by msgb and mgcp */
 | 
					/* used by msgb and mgcp */
 | 
				
			||||||
void *tall_mgw_ctx = NULL;
 | 
					void *tall_mgw_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_help()
 | 
					static void print_help(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	printf("Some useful options:\n");
 | 
						printf("Some useful options:\n");
 | 
				
			||||||
	printf(" -h --help is printing this text.\n");
 | 
						printf(" -h --help is printing this text.\n");
 | 
				
			||||||
@@ -235,7 +234,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,24 +242,13 @@ 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]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_vty_is_config_node(struct vty *vty, int node)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	switch (node) {
 | 
					 | 
				
			||||||
	case CONFIG_NODE:
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_vty_go_parent(struct vty *vty)
 | 
					int mgcp_vty_go_parent(struct vty *vty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (vty->node) {
 | 
						switch (vty->node) {
 | 
				
			||||||
@@ -270,7 +258,7 @@ int mgcp_vty_go_parent(struct vty *vty)
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MGCP_NODE:
 | 
						case MGCP_NODE:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		if (mgcp_vty_is_config_node(vty, vty->node))
 | 
							if (vty->node != CONFIG_NODE)
 | 
				
			||||||
			vty->node = CONFIG_NODE;
 | 
								vty->node = CONFIG_NODE;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			vty->node = ENABLE_NODE;
 | 
								vty->node = ENABLE_NODE;
 | 
				
			||||||
@@ -281,12 +269,36 @@ int mgcp_vty_go_parent(struct vty *vty)
 | 
				
			|||||||
	return vty->node;
 | 
						return vty->node;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void signal_handler(int signum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stdout, "signal %u received\n", signum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (signum) {
 | 
				
			||||||
 | 
						case SIGABRT:
 | 
				
			||||||
 | 
							/* in case of abort, we want to obtain a talloc report and
 | 
				
			||||||
 | 
							 * then run default SIGABRT handler, who will generate coredump
 | 
				
			||||||
 | 
							 * and abort the process. abort() should do this for us after we
 | 
				
			||||||
 | 
							 * return, but program wouldn't exit if an external SIGABRT is
 | 
				
			||||||
 | 
							 * received.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_mgw_ctx, stderr);
 | 
				
			||||||
 | 
							signal(SIGABRT, SIG_DFL);
 | 
				
			||||||
 | 
							raise(SIGABRT);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGUSR1:
 | 
				
			||||||
 | 
							talloc_report(tall_vty_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_mgw_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct vty_app_info vty_info = {
 | 
					static struct vty_app_info vty_info = {
 | 
				
			||||||
	.name 		= "OsmoMGW",
 | 
						.name 		= "OsmoMGW",
 | 
				
			||||||
	.version	= PACKAGE_VERSION,
 | 
						.version	= PACKAGE_VERSION,
 | 
				
			||||||
	.go_parent_cb	= mgcp_vty_go_parent,
 | 
						.go_parent_cb	= mgcp_vty_go_parent,
 | 
				
			||||||
	.is_config_node	= mgcp_vty_is_config_node,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat log_categories[] = {
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
@@ -295,13 +307,22 @@ static const struct log_info_cat log_categories[] = {
 | 
				
			|||||||
		  .name = "DRTP",
 | 
							  .name = "DRTP",
 | 
				
			||||||
		  .description = "RTP stream handling",
 | 
							  .description = "RTP stream handling",
 | 
				
			||||||
		  .color = "\033[1;30m",
 | 
							  .color = "\033[1;30m",
 | 
				
			||||||
		  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
							  .enabled = 1,
 | 
				
			||||||
 | 
							  .loglevel = LOGL_NOTICE,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	[DE1] = {
 | 
						[DE1] = {
 | 
				
			||||||
		  .name = "DE1",
 | 
							  .name = "DE1",
 | 
				
			||||||
		  .description = "E1 line handling",
 | 
							  .description = "E1 line handling",
 | 
				
			||||||
		  .color = "\033[1;31m",
 | 
							  .color = "\033[1;31m",
 | 
				
			||||||
		  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
							  .enabled = 1,
 | 
				
			||||||
 | 
							  .loglevel = LOGL_NOTICE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[DOSMUX] = {
 | 
				
			||||||
 | 
							  .name = "DOSMUX",
 | 
				
			||||||
 | 
							  .description = "Osmux (Osmocom RTP multiplexing)",
 | 
				
			||||||
 | 
							  .color = "\033[1;32m",
 | 
				
			||||||
 | 
							  .enabled = 1,
 | 
				
			||||||
 | 
							  .loglevel = LOGL_NOTICE,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -320,6 +341,8 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	msgb_talloc_ctx_init(tall_mgw_ctx, 0);
 | 
						msgb_talloc_ctx_init(tall_mgw_ctx, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						signal(SIGABRT, &signal_handler);
 | 
				
			||||||
 | 
						signal(SIGUSR1, &signal_handler);
 | 
				
			||||||
	osmo_init_ignore_signals();
 | 
						osmo_init_ignore_signals();
 | 
				
			||||||
	osmo_init_logging2(tall_mgw_ctx, &log_info);
 | 
						osmo_init_logging2(tall_mgw_ctx, &log_info);
 | 
				
			||||||
	libosmo_abis_init(tall_mgw_ctx);
 | 
						libosmo_abis_init(tall_mgw_ctx);
 | 
				
			||||||
@@ -352,12 +375,11 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* start telnet after reading config for vty_get_bind_addr() */
 | 
						/* start telnet after reading config for vty_get_bind_addr() */
 | 
				
			||||||
	rc = telnet_init_dynif(tall_mgw_ctx, NULL,
 | 
						rc = telnet_init_default(tall_mgw_ctx, NULL, OSMO_VTY_PORT_MGW);
 | 
				
			||||||
			       vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
 | 
					 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
						cfg->ctrl = ctrl_interface_setup(cfg, OSMO_CTRL_PORT_MGW, NULL);
 | 
				
			||||||
	if (!cfg->ctrl) {
 | 
						if (!cfg->ctrl) {
 | 
				
			||||||
		fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
							fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
				
			||||||
			ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
								ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
				
			||||||
@@ -369,12 +391,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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,11 +34,11 @@ DISTCLEANFILES = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if ENABLE_EXT_TESTS
 | 
					if ENABLE_EXT_TESTS
 | 
				
			||||||
python-tests: $(BUILT_SOURCES)
 | 
					python-tests: $(top_builddir)/src/osmo-mgw/osmo-mgw
 | 
				
			||||||
	osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
						osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
				
			||||||
	osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
						osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
python-tests: $(BUILT_SOURCES)
 | 
					python-tests:
 | 
				
			||||||
	echo "Not running python-based tests (determined at configure-time)"
 | 
						echo "Not running python-based tests (determined at configure-time)"
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,13 +18,14 @@ AM_CFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
 | 
						-no-install \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
	mgcp_test.ok \
 | 
						mgcp_test.ok \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
noinst_PROGRAMS = \
 | 
					check_PROGRAMS = \
 | 
				
			||||||
	mgcp_test \
 | 
						mgcp_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,3 +45,6 @@ mgcp_test_LDADD = \
 | 
				
			|||||||
	$(LIBOSMONETIF_LIBS) \
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
	-lm  \
 | 
						-lm  \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update_exp:
 | 
				
			||||||
 | 
						$(builddir)/mgcp_test >$(srcdir)/mgcp_test.ok
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -73,7 +73,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -97,21 +97,46 @@ 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
 | 
				
			||||||
M: sendrecv
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
o=- %s 23 IN IP4 0.0.0.0
 | 
					o=- %s 23 IN IP4 0.0.0.0
 | 
				
			||||||
c=IN IP4 0.0.0.0
 | 
					c=IN IP4 0.0.0.0
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains 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:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -124,18 +149,19 @@ Dummy packets: 2
 | 
				
			|||||||
Testing MDCX4_PT1
 | 
					Testing MDCX4_PT1
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
---------8<---------
 | 
					MDCX 18983218 1@mgw MGCP 1.0
 | 
				
			||||||
MDCX 18983217 1@mgw MGCP 1.0
 | 
					M: SENDRECV
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20-40, a:AMR, nt:IN
 | 
					L: p:20-40, a:AMR, nt:IN
 | 
				
			||||||
I: %s
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
v=0
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -148,18 +174,19 @@ Dummy packets: 2
 | 
				
			|||||||
Testing MDCX4_PT2
 | 
					Testing MDCX4_PT2
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					MDCX 18983219 1@mgw MGCP 1.0
 | 
				
			||||||
---------8<---------
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20-20, a:AMR, nt:IN
 | 
					L: p:20-20, a:AMR, nt:IN
 | 
				
			||||||
C: 2
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
L: p:20-20, a:AMR, nt:IN
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
t=0 0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -172,18 +199,19 @@ Dummy packets: 2
 | 
				
			|||||||
Testing MDCX4_PT3
 | 
					Testing MDCX4_PT3
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
Testing MDCX4_PT3
 | 
					MDCX 18983220 1@mgw MGCP 1.0
 | 
				
			||||||
creating message from statically defined input:
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: a:AMR, nt:IN
 | 
					L: a:AMR, nt:IN
 | 
				
			||||||
M: sendrecv
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
I: %s
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
L: a:AMR, nt:IN
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
c=IN IP4 0.0.0.0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -196,18 +224,19 @@ 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
 | 
				
			||||||
Testing MDCX4_PT4
 | 
					m: sendrecv
 | 
				
			||||||
 | 
					c: 2
 | 
				
			||||||
i: %s
 | 
					i: %s
 | 
				
			||||||
l: A:amr, NT:IN
 | 
					l: A:amr, NT:IN
 | 
				
			||||||
MDCX 18983220 1@mgw MGCP 1.0
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
c: 2
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
i: %s
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
o=- %s 23 IN IP4 0.0.0.0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -220,18 +249,19 @@ Dummy packets: 2
 | 
				
			|||||||
Testing MDCX4_SO
 | 
					Testing MDCX4_SO
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
 | 
					MDCX 18983222 1@mgw MGCP 1.0
 | 
				
			||||||
================================================
 | 
					M: sendonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
---------8<---------
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
M: sendonly
 | 
					o=- %s 23 IN IP4 5.6.7.8
 | 
				
			||||||
C: 2
 | 
					c=IN IP4 5.6.7.8
 | 
				
			||||||
t=0 0
 | 
					t=0 0
 | 
				
			||||||
m=audio 4441 RTP/AVP 99
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
a=rtpmap:99 AMR/8000
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
v=0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -243,8 +273,9 @@ Response matches our expectations.
 | 
				
			|||||||
Testing MDCX4_RO
 | 
					Testing MDCX4_RO
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
(response contains a connection id)
 | 
					MDCX 18983223 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
L: p:20, a:AMR, nt:IN
 | 
					L: p:20, a:AMR, nt:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,9 +304,15 @@ Response matches our expectations.
 | 
				
			|||||||
Testing CRCX_ZYN
 | 
					Testing CRCX_ZYN
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
Response matches our expectations.
 | 
					CRCX 2 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
@@ -391,7 +428,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing CRCX
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -441,7 +478,6 @@ checking response:
 | 
				
			|||||||
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)
 | 
				
			||||||
Testing CRCX
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing CRCX
 | 
					Testing CRCX
 | 
				
			||||||
@@ -457,7 +493,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
creating message from statically defined input:
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -470,7 +506,7 @@ Dummy packets: 2
 | 
				
			|||||||
Testing MDCX_TOO_LONG_CI
 | 
					Testing MDCX_TOO_LONG_CI
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
 | 
					MDCX 18983224 1@mgw MGCP 1.0
 | 
				
			||||||
I: 123456789012345678901234567890123
 | 
					I: 123456789012345678901234567890123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
@@ -503,6 +539,184 @@ Response matches our expectations.
 | 
				
			|||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing AUEP_NULL
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					AUEP 18983215 null@mgw MGCP 1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_NULL
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 2 null@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing MDCX_NULL
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					MDCX 9 null@mgw MGCP 1.0
 | 
				
			||||||
 | 
					I: %s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing DLCX_NULL
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					DLCX 8 null@mgw MGCP 1.0
 | 
				
			||||||
 | 
					I: %s
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing RQNT_NULL
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					RQNT 186908782 null@mgw MGCP 1.0
 | 
				
			||||||
 | 
					X: B244F267488
 | 
				
			||||||
 | 
					S: D/9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 3 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 97
 | 
				
			||||||
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV2
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					a=sendrecv
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX_PORT_0_IUFP_SENDRECV3
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 4 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 0 RTP/AVP 96
 | 
				
			||||||
 | 
					a=rtpmap:96 VND.3GPP.IUFP/16000
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing CRCX
 | 
					Testing CRCX
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -516,7 +730,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing CRCX
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -534,7 +748,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Re-transmitting CRCX
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -646,7 +860,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing packet loss calculation.
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -770,6 +984,15 @@ 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
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 180320, dTS: 0, Seq: 1003
 | 
				
			||||||
 | 
					Out TS change: 20000, dTS: 0, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180480, dTS: 160, Seq: 1004
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180640, dTS: 160, Seq: 1005
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 5, Transit = -163760
 | 
				
			||||||
Testing packet error detection.
 | 
					Testing packet error detection.
 | 
				
			||||||
Output SSRC changed to 11223344
 | 
					Output SSRC changed to 11223344
 | 
				
			||||||
In TS: 0, dTS: 0, Seq: 0
 | 
					In TS: 0, dTS: 0, Seq: 0
 | 
				
			||||||
@@ -864,6 +1087,15 @@ 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
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 180320, dTS: 0, Seq: 1003
 | 
				
			||||||
 | 
					Out TS change: 20000, dTS: 0, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180480, dTS: 160, Seq: 1004
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180640, dTS: 160, Seq: 1005
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 5, Transit = -163760
 | 
				
			||||||
Testing packet error detection, patch timestamps.
 | 
					Testing packet error detection, patch timestamps.
 | 
				
			||||||
Output SSRC changed to 11223344
 | 
					Output SSRC changed to 11223344
 | 
				
			||||||
In TS: 0, dTS: 0, Seq: 0
 | 
					In TS: 0, dTS: 0, Seq: 0
 | 
				
			||||||
@@ -958,6 +1190,15 @@ 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
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 180320, dTS: 0, Seq: 1003
 | 
				
			||||||
 | 
					Out TS change: 20000, dTS: 0, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180480, dTS: 160, Seq: 1004
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180640, dTS: 160, Seq: 1005
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 5, Transit = -163760
 | 
				
			||||||
Testing packet error detection, patch SSRC, patch timestamps.
 | 
					Testing packet error detection, patch SSRC, patch timestamps.
 | 
				
			||||||
Output SSRC changed to 11223344
 | 
					Output SSRC changed to 11223344
 | 
				
			||||||
In TS: 0, dTS: 0, Seq: 0
 | 
					In TS: 0, dTS: 0, Seq: 0
 | 
				
			||||||
@@ -1050,6 +1291,15 @@ 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
 | 
				
			||||||
Stats: Jitter = 0, Transit = -144000
 | 
					Stats: Jitter = 0, Transit = -144000
 | 
				
			||||||
 | 
					In TS: 180320, dTS: 0, Seq: 1003
 | 
				
			||||||
 | 
					Out TS change: 20000, dTS: 0, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180480, dTS: 160, Seq: 1004
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 0, Transit = -163840
 | 
				
			||||||
 | 
					In TS: 180640, dTS: 160, Seq: 1005
 | 
				
			||||||
 | 
					Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
 | 
				
			||||||
 | 
					Stats: Jitter = 5, Transit = -163760
 | 
				
			||||||
Testing multiple payload types
 | 
					Testing multiple payload types
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
@@ -1064,7 +1314,7 @@ c=IN IP4 123.12.12.123
 | 
				
			|||||||
m=audio 5904 RTP/AVP 18 97
 | 
					m=audio 5904 RTP/AVP 18 97
 | 
				
			||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
---------8<---------
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1081,7 +1331,7 @@ m=audio 5904 RTP/AVP 18 97 101
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
CRCX 2 2@mgw MGCP 1.0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1098,7 +1348,7 @@ m=audio 5904 RTP/AVP
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
CRCX 2 3@mgw MGCP 1.0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1115,7 +1365,7 @@ m=audio 5904 RTP/AVP 18
 | 
				
			|||||||
a=rtpmap:18 G729/8000
 | 
					a=rtpmap:18 G729/8000
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=rtpmap:101 FOO/8000
 | 
					a=rtpmap:101 FOO/8000
 | 
				
			||||||
CRCX 2 4@mgw MGCP 1.0
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -1197,7 +1447,7 @@ v=0
 | 
				
			|||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
Testing no rtpmap name
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
@@ -1218,7 +1468,7 @@ p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			|||||||
p10, aPCMU -> (null)
 | 
					p10, aPCMU -> (null)
 | 
				
			||||||
'10,a :PCMU' -> '(null)'
 | 
					'10,a :PCMU' -> '(null)'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
 | 
					Testing mgcp_codec_find_convertible()
 | 
				
			||||||
#0: same order, but differing payload type numbers
 | 
					#0: same order, but differing payload type numbers
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
@@ -1228,13 +1478,15 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
'10,a :PCMU' -> '(null)'
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
Testing mgcp_codec_pt_translate()
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
#0: same order, but differing payload type numbers
 | 
					    conn[1]: codec:AMR, pt:96
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    conn[1]: codec:AMR, pt:96
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
#1: different order and different payload type numbers
 | 
					#1: different order and different payload type numbers
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
@@ -1244,13 +1496,15 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
					    conn[0]: codec:PCMU, pt:0
 | 
				
			||||||
#1: different order and different payload type numbers
 | 
					    conn[1]: codec:PCMU, pt:0
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    conn[1]: codec:GSM-HR-08, pt:97
 | 
				
			||||||
 | 
					    conn[0]: codec:GSM-HR-08, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
					#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
@@ -1260,12 +1514,15 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
					    conn[0]: codec:PCMU, pt:0
 | 
				
			||||||
#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
					    conn[1]: codec:PCMU, pt:0
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:GSM-HR-08, pt:97
 | 
				
			||||||
 | 
					    conn[0]: codec:GSM-HR-08, pt:96
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
#3: conn0 has no codecs
 | 
					#3: conn0 has no codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    (none)
 | 
					    (none)
 | 
				
			||||||
@@ -1273,9 +1530,13 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
 | 
					    codec decision failed (expected)!
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:96
 | 
				
			||||||
 | 
					    conn[0]: codec:none, pt:none
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
#4: conn1 has no codecs
 | 
					#4: conn1 has no codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
@@ -1283,39 +1544,116 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    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)
 | 
				
			||||||
    1:   0 PCMU/8000/1  -> rc=0
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					    conn[1]: codec:none, pt:none
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    codec decision failed (expected)!
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#5: test AMR with differing octet-aligned settings (both <-> both)
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
    (none)
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					    conn[1]: codec:AMR, pt:121
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#6: test AMR with differing octet-aligned settings (oa <-> both)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:121
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:121
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#7: test AMR with differing octet-aligned settings (bwe <-> both)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#8: test AMR with missing octet-aligned settings (oa <-> unset)
 | 
				
			||||||
 - 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
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 121
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#9: test AMR with missing octet-aligned settings (bwe <-> unset)
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
 | 
					    0: 111 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#10: test AMR with NULL param (oa <-> null)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 112 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000  -> rc=0
 | 
					    0: 122 AMR/8000  -> rc=0
 | 
				
			||||||
    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - add codecs on conn1:
 | 
					    Codec decision result:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#11: test AMR with NULL param (bwe <-> null)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:AMR, pt:122
 | 
				
			||||||
 | 
					    conn[0]: codec:AMR, pt:112
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#12: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
@@ -1324,14 +1662,16 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  97 GSM-HR-08/8000  -> rc=0
 | 
					    0:  97 GSM-HR-08/8000  -> rc=0
 | 
				
			||||||
    1:   0 PCMU/8000  -> rc=0
 | 
					    1:   0 PCMU/8000  -> rc=0
 | 
				
			||||||
    2:  96 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
 | 
					    conn[0]: codec:PCMU, pt:0
 | 
				
			||||||
#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
 | 
					    conn[1]: codec:PCMU, pt:0
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    conn[1]: codec:GSM-HR-08, pt:97
 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    conn[0]: codec:GSM-HR-08, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#13: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
@@ -1340,14 +1680,16 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
    0:  97 GSM-HR-08  -> rc=0
 | 
					    0:  97 GSM-HR-08  -> rc=0
 | 
				
			||||||
    1:   0 PCMU  -> rc=0
 | 
					    1:   0 PCMU  -> rc=0
 | 
				
			||||||
    2:  96 AMR octet-aligned=1  -> rc=0
 | 
					    2:  96 AMR octet-aligned=1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
					    conn[0]: codec:PCMU, pt:0
 | 
				
			||||||
#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
 | 
					    conn[1]: codec:PCMU, pt:0
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
    0:   0 PCMU/8000/1  -> rc=0
 | 
					    Codec decision result:
 | 
				
			||||||
    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
					    conn[1]: codec:GSM-HR-08, pt:97
 | 
				
			||||||
    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    conn[0]: codec:GSM-HR-08, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					#14: test whether channel number matching is waterproof
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 GSM-HR-08/8000  -> rc=0
 | 
					    0: 111 GSM-HR-08/8000  -> rc=0
 | 
				
			||||||
    1: 112 GSM-HR-08/8000/2  -> rc=-22
 | 
					    1: 112 GSM-HR-08/8000/2  -> rc=-22
 | 
				
			||||||
@@ -1355,10 +1697,15 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
 - add codecs on conn1:
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 GSM-HR-08/8000/2  -> rc=-22
 | 
					    0: 122 GSM-HR-08/8000/2  -> rc=-22
 | 
				
			||||||
    1: 121 GSM-HR-08/8000/1  -> rc=0
 | 
					    1: 121 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
					 - mgcp_codec_decide(&conn[0], &conn[1]):
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
					    Codec decision result:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
					    conn[0]: codec:GSM-HR-08, pt:111
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
					    conn[1]: codec:GSM-HR-08, pt:121
 | 
				
			||||||
 | 
					 - mgcp_codec_decide(&conn[1], &conn[0]):
 | 
				
			||||||
 | 
					    Codec decision result:
 | 
				
			||||||
 | 
					    conn[1]: codec:GSM-HR-08, pt:121
 | 
				
			||||||
 | 
					    conn[0]: codec:GSM-HR-08, pt:111
 | 
				
			||||||
 | 
					 ===> SUCCESS: codec decision as expected!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing test_conn_id_matching
 | 
					Testing test_conn_id_matching
 | 
				
			||||||
needle='23AB' found '000023AB'
 | 
					needle='23AB' found '000023AB'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ AM_CFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AM_LDFLAGS = \
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
 | 
						-no-install \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTRA_DIST = \
 | 
					EXTRA_DIST = \
 | 
				
			||||||
@@ -22,7 +23,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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ static struct msgb *from_str(const char *str)
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_client_conf conf;
 | 
					static struct mgcp_client_conf *conf;
 | 
				
			||||||
struct mgcp_client *mgcp = NULL;
 | 
					struct mgcp_client *mgcp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
 | 
					static int reply_to(mgcp_trans_id_t trans_id, int code, const char *comment,
 | 
				
			||||||
@@ -107,9 +107,6 @@ void test_response_cb(struct mgcp_response *response, void *priv)
 | 
				
			|||||||
	printf("  audio_port = %u\n", response->audio_port);
 | 
						printf("  audio_port = %u\n", response->audio_port);
 | 
				
			||||||
	printf("  audio_ip = %s\n", response->audio_ip);
 | 
						printf("  audio_ip = %s\n", response->audio_ip);
 | 
				
			||||||
	printf("  ptime = %u\n", response->ptime);
 | 
						printf("  ptime = %u\n", response->ptime);
 | 
				
			||||||
	printf("  codecs_len = %u\n", response->codecs_len);
 | 
					 | 
				
			||||||
	for(i=0;i<response->codecs_len;i++)
 | 
					 | 
				
			||||||
		printf("  codecs[%u] = %u\n", i, response->codecs[i]);
 | 
					 | 
				
			||||||
	printf("  ptmap_len = %u\n", response->ptmap_len);
 | 
						printf("  ptmap_len = %u\n", response->ptmap_len);
 | 
				
			||||||
	for(i=0;i<response->ptmap_len;i++) {
 | 
						for(i=0;i<response->ptmap_len;i++) {
 | 
				
			||||||
		printf("  ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
 | 
							printf("  ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
 | 
				
			||||||
@@ -149,12 +146,11 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
		.conn_id = "11",
 | 
							.conn_id = "11",
 | 
				
			||||||
		.conn_mode = MGCP_CONN_RECV_SEND,
 | 
							.conn_mode = MGCP_CONN_RECV_SEND,
 | 
				
			||||||
		.ptime = 20,
 | 
							.ptime = 20,
 | 
				
			||||||
		.codecs[0] = CODEC_GSM_8000_1,
 | 
							.ptmap = {
 | 
				
			||||||
		.codecs[1] = CODEC_AMR_8000_1,
 | 
								{ .codec = CODEC_GSM_8000_1, .pt = CODEC_GSM_8000_1 },
 | 
				
			||||||
		.codecs[2] = CODEC_GSMEFR_8000_1,
 | 
								{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
 | 
				
			||||||
		.codecs_len = 1,
 | 
								{ .codec = CODEC_GSMEFR_8000_1, .pt = 96 },
 | 
				
			||||||
		.ptmap[0].codec = CODEC_GSMEFR_8000_1,
 | 
							},
 | 
				
			||||||
		.ptmap[0].pt = 96,
 | 
					 | 
				
			||||||
		.ptmap_len = 1,
 | 
							.ptmap_len = 1,
 | 
				
			||||||
		.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
							.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
				
			||||||
		.x_osmo_osmux_cid = -1, /* wildcard */
 | 
							.x_osmo_osmux_cid = -1, /* wildcard */
 | 
				
			||||||
@@ -162,7 +158,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, &conf);
 | 
						mgcp = mgcp_client_init(ctx, conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n");
 | 
						printf("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -179,9 +175,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	mgcp_msg.presence =
 | 
						mgcp_msg.presence =
 | 
				
			||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
				
			||||||
	mgcp_msg.codecs_len = 2;
 | 
						mgcp_msg.ptmap_len = 2;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated CRCX message (three codecs, one with custom pt):\n");
 | 
						printf("Generated CRCX message (three codecs, one with custom pt):\n");
 | 
				
			||||||
@@ -189,9 +185,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	mgcp_msg.presence =
 | 
						mgcp_msg.presence =
 | 
				
			||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
 | 
				
			||||||
	mgcp_msg.codecs_len = 3;
 | 
						mgcp_msg.ptmap_len = 3;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated MDCX message:\n");
 | 
						printf("Generated MDCX message:\n");
 | 
				
			||||||
@@ -209,9 +205,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
	mgcp_msg.codecs_len = 2;
 | 
						mgcp_msg.ptmap_len = 2;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated MDCX message (three codecs, one with custom pt):\n");
 | 
						printf("Generated MDCX message (three codecs, one with custom pt):\n");
 | 
				
			||||||
@@ -220,9 +216,9 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
	mgcp_msg.codecs_len = 3;
 | 
						mgcp_msg.ptmap_len = 3;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	mgcp_msg.codecs_len = 1;
 | 
						mgcp_msg.ptmap_len = 1;
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Generated DLCX message:\n");
 | 
						printf("Generated DLCX message:\n");
 | 
				
			||||||
@@ -315,7 +311,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_mgcp_client_cancel()
 | 
					void test_mgcp_client_cancel(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
@@ -330,8 +326,10 @@ void test_mgcp_client_cancel()
 | 
				
			|||||||
		.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
 | 
							.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID
 | 
				
			||||||
			     | MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
 | 
								     | MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
 | 
				
			||||||
		.ptime = 20,
 | 
							.ptime = 20,
 | 
				
			||||||
		.codecs[0] = CODEC_AMR_8000_1,
 | 
							.ptmap = {
 | 
				
			||||||
		.codecs_len = 1
 | 
								{ .codec = CODEC_AMR_8000_1, .pt = CODEC_AMR_8000_1 },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.ptmap_len = 1
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n%s():\n", __func__);
 | 
						printf("\n%s():\n", __func__);
 | 
				
			||||||
@@ -339,7 +337,7 @@ void test_mgcp_client_cancel()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, &conf);
 | 
						mgcp = mgcp_client_init(ctx, conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	trans_id = mgcp_msg_trans_id(msg);
 | 
						trans_id = mgcp_msg_trans_id(msg);
 | 
				
			||||||
@@ -487,7 +485,7 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_sdp_section_start()
 | 
					void test_sdp_section_start(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	int failures = 0;
 | 
						int failures = 0;
 | 
				
			||||||
@@ -531,7 +529,7 @@ void test_sdp_section_start()
 | 
				
			|||||||
	OSMO_ASSERT(!failures);
 | 
						OSMO_ASSERT(!failures);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_map_pt_to_codec(void)
 | 
					static void test_map_str_to_codec(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Full form */
 | 
						/* Full form */
 | 
				
			||||||
	OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
 | 
						OSMO_ASSERT(map_str_to_codec("PCMU/8000/1") == CODEC_PCMU_8000_1);
 | 
				
			||||||
@@ -630,7 +628,7 @@ void test_mgcp_client_e1_epname(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
		talloc_free(mgcp);
 | 
							talloc_free(mgcp);
 | 
				
			||||||
	mgcp = mgcp_client_init(ctx, &conf);
 | 
						mgcp = mgcp_client_init(ctx, conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Valid endpoint names */
 | 
						/* Valid endpoint names */
 | 
				
			||||||
	epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
 | 
				
			||||||
@@ -675,6 +673,214 @@ void test_mgcp_client_e1_epname(void)
 | 
				
			|||||||
	OSMO_ASSERT(epname == NULL);
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct parse_response_test {
 | 
				
			||||||
 | 
						const char *body;
 | 
				
			||||||
 | 
						int expect_rc;
 | 
				
			||||||
 | 
						struct mgcp_response expect_params;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct parse_response_test parse_response_tests[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 112 3\r\n" /* <-- implicit: 3 = GSM-FR */
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 112 3\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:3 GSM/8000\r\n" /* 3 == GSM-FR implicitly, is an explicit entry a problem? */
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 }, /* no, not a problem */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 3\r\n" /* <-- 112 is missing here. Will it still appear? */
 | 
				
			||||||
 | 
								"a=rtpmap:112 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_GSM_8000_1, .pt = 3 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 112 }, /* <-- yes, it was added to the end. */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 2,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* test MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\n" /* <-- 10 codecs max */
 | 
				
			||||||
 | 
								"a=rtpmap:101 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:102 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:103 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:104 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:105 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:106 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:107 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:108 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:109 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:110 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_port = 23,
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
								.ptmap = {
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 101 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 102 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 103 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 104 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 105 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 106 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 107 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 108 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 109 },
 | 
				
			||||||
 | 
									{ .codec = CODEC_AMR_8000_1, .pt = 110 },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								.ptmap_len = 10,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* test MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
							.body = "200 2 OK\r\n"
 | 
				
			||||||
 | 
								"I: foo\r\n"
 | 
				
			||||||
 | 
								"\r\n"
 | 
				
			||||||
 | 
								"v=0\r\n"
 | 
				
			||||||
 | 
								"o=- name 23 IN IP4 0.0.0.0\r\n"
 | 
				
			||||||
 | 
								"s=-\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
								"t=0 0\r\n"
 | 
				
			||||||
 | 
								"m=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\n" /* <-- 11 > MGCP_MAX_CODECS */
 | 
				
			||||||
 | 
								"a=rtpmap:101 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:102 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:103 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:104 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:105 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:106 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:107 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:108 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:109 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=rtpmap:110 AMR/8000\r\n"
 | 
				
			||||||
 | 
								"a=ptime:20\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -EINVAL,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_parse_response(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int failures = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(parse_response_tests); i++) {
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
							struct parse_response_test *t = &parse_response_tests[i];
 | 
				
			||||||
 | 
							struct mgcp_response *r = talloc_zero(ctx, struct mgcp_response);
 | 
				
			||||||
 | 
							int p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r->body = talloc_strdup(r, t->body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//printf("\n%s() test [%d]:\n", __func__, i);
 | 
				
			||||||
 | 
							fprintf(stderr, "\n%s() test [%d]:\n", __func__, i);
 | 
				
			||||||
 | 
							fprintf(stderr, "body: \"%s\"\n", osmo_escape_str(r->body, -1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = mgcp_response_parse_params(r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fprintf(stderr, "got rc=%d\n", rc);
 | 
				
			||||||
 | 
							if (rc != t->expect_rc) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected rc=%d\n", t->expect_rc);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (rc) {
 | 
				
			||||||
 | 
								talloc_free(r);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
 | 
				
			||||||
 | 
							if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fprintf(stderr, "got audio_port=%u\n", r->audio_port);
 | 
				
			||||||
 | 
							if (r->audio_port != t->expect_params.audio_port) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (p = 0; p < r->ptmap_len; p++) {
 | 
				
			||||||
 | 
								struct ptmap *got = &r->ptmap[p];
 | 
				
			||||||
 | 
								struct ptmap *expect = NULL;
 | 
				
			||||||
 | 
								fprintf(stderr, "  %d %s\n", got->pt, osmo_mgcpc_codec_name(got->codec));
 | 
				
			||||||
 | 
								if (p >= t->expect_params.ptmap_len) {
 | 
				
			||||||
 | 
									fprintf(stderr, "    - ERROR: too many codec entries\n");
 | 
				
			||||||
 | 
									failures++;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								expect = &t->expect_params.ptmap[p];
 | 
				
			||||||
 | 
								if (ptmap_cmp(got, expect)) {
 | 
				
			||||||
 | 
									fprintf(stderr, "    - ERROR: expected: %d %s\n",
 | 
				
			||||||
 | 
										expect->pt, osmo_mgcpc_codec_name(expect->codec));
 | 
				
			||||||
 | 
									failures++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							talloc_free(r);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(!failures);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat log_categories[] = {
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -697,15 +903,17 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
 | 
						log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_client_conf_init(&conf);
 | 
						conf = mgcp_client_conf_alloc(ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test_mgcp_msg();
 | 
						test_mgcp_msg();
 | 
				
			||||||
	test_mgcp_client_cancel();
 | 
						test_mgcp_client_cancel();
 | 
				
			||||||
	test_sdp_section_start();
 | 
						test_sdp_section_start();
 | 
				
			||||||
	test_map_codec_to_pt_and_map_pt_to_codec();
 | 
						test_map_codec_to_pt_and_map_pt_to_codec();
 | 
				
			||||||
	test_map_pt_to_codec();
 | 
						test_map_str_to_codec();
 | 
				
			||||||
	test_mgcp_client_e1_epname();
 | 
						test_mgcp_client_e1_epname();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_parse_response();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Done\n");
 | 
						printf("Done\n");
 | 
				
			||||||
	fprintf(stderr, "Done\n");
 | 
						fprintf(stderr, "Done\n");
 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,21 @@
 | 
				
			|||||||
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 too small, can not generate MGCP message (SDP)
 | 
				
			||||||
 | 
					DLMGCP MGW(mgw) Failed to add SDP, can not generate MGCP message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_mgcp_client_cancel():
 | 
					test_mgcp_client_cancel():
 | 
				
			||||||
DLMGCP 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 link to MGW now considered UP
 | 
				
			||||||
 | 
					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 +132,56 @@ 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!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [0]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [1]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 112 3\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:3 GSM/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [2]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 3\r\na=rtpmap:112 AMR/8000\r\na=ptime:20\r\n"
 | 
				
			||||||
 | 
					DLMGCP error in MGCP message: 'a=rtpmap:112' has no matching entry in 'm=audio ... 112'
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  3 GSM/8000/1
 | 
				
			||||||
 | 
					  112 AMR/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [3]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR/8"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					  101 AMR/8000/1
 | 
				
			||||||
 | 
					  102 AMR/8000/1
 | 
				
			||||||
 | 
					  103 AMR/8000/1
 | 
				
			||||||
 | 
					  104 AMR/8000/1
 | 
				
			||||||
 | 
					  105 AMR/8000/1
 | 
				
			||||||
 | 
					  106 AMR/8000/1
 | 
				
			||||||
 | 
					  107 AMR/8000/1
 | 
				
			||||||
 | 
					  108 AMR/8000/1
 | 
				
			||||||
 | 
					  109 AMR/8000/1
 | 
				
			||||||
 | 
					  110 AMR/8000/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_parse_response() test [4]:
 | 
				
			||||||
 | 
					body: "200 2 OK\r\nI: foo\r\n\r\nv=0\r\no=- name 23 IN IP4 0.0.0.0\r\ns=-\r\nc=IN IP4 1.2.3.4\r\nt=0 0\r\nm=audio 23 RTP/AVP 101 102 103 104 105 106 107 108 109 110 3\r\na=rtpmap:101 AMR/8000\r\na=rtpmap:102 AMR/8000\r\na=rtpmap:103 AMR/8000\r\na=rtpmap:104 AMR"
 | 
				
			||||||
 | 
					DLMGCP SDP: can parse only up to 10 payload type numbers
 | 
				
			||||||
 | 
					DLMGCP Failed to parse SDP parameter payload types (RTP/AVP)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
Done
 | 
					Done
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user