mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 08:12:01 +00:00
Compare commits
452 Commits
stsp/show_
...
laforge/rt
Author | SHA1 | Date | |
---|---|---|---|
|
b7a0e043b5 | ||
|
004ea1398a | ||
|
4f0d72d4c1 | ||
|
c7d15fb70d | ||
|
172f5acfce | ||
|
fdbefde869 | ||
|
25ecc91c3b | ||
|
995529548b | ||
|
0c04500ac5 | ||
|
a0b69f1896 | ||
|
fbf78d13f1 | ||
|
df9192efee | ||
|
70a658a2ba | ||
|
2764bdb1aa | ||
|
55fdfc223e | ||
|
8f33303660 | ||
|
a94c56e4c6 | ||
|
2ebcf5c34a | ||
|
f936e10f07 | ||
|
e303fa9ff3 | ||
|
958f5e74cc | ||
|
1e8d5fa44b | ||
|
374ad788d8 | ||
|
da07b90f0f | ||
|
fa495d669f | ||
|
439c86fc58 | ||
|
74e83d3d82 | ||
|
d55be05af1 | ||
|
8f91a7f450 | ||
|
da3a5759e1 | ||
|
29e671f257 | ||
|
d6a7e17911 | ||
|
3f4a4cb49c | ||
|
3d2b76fd95 | ||
|
276a414aa3 | ||
|
c534ad17dc | ||
|
3f2c15f275 | ||
|
38533ba9b3 | ||
|
39889e4389 | ||
|
c824fe4eb0 | ||
|
124a3e0b34 | ||
|
96c6e06681 | ||
|
ce18705875 | ||
|
41ab87f67c | ||
|
a8739fc7be | ||
|
21dfeff8aa | ||
|
f486e741a4 | ||
|
268568593e | ||
|
41d59205c0 | ||
|
036612b035 | ||
|
6bad138c96 | ||
|
8dc3597085 | ||
|
d70eef6421 | ||
|
33d97f721d | ||
|
d57310731f | ||
|
a8c684b51f | ||
|
03fcc91aad | ||
|
9de30e7cc4 | ||
|
d64c041cdb | ||
|
d02716d6c2 | ||
|
a065e632c0 | ||
|
bd060c3c99 | ||
|
97cae477fb | ||
|
02c880a7dd | ||
|
ba09687768 | ||
|
a4b677c45a | ||
|
6b7afe8f57 | ||
|
4131a65c4d | ||
|
6a5e5ac2d4 | ||
|
b066bd0c86 | ||
|
d6769ea207 | ||
|
ca280a1a84 | ||
|
a24dcc61d7 | ||
|
62d9df684f | ||
|
8358c4ba07 | ||
|
4c77e9b748 | ||
|
33347a4f5d | ||
|
7d86d4c523 | ||
|
eb984bd630 | ||
|
b3d14eb552 | ||
|
907744e2fc | ||
|
776846a0b9 | ||
|
59e7cf4437 | ||
|
b2064423fe | ||
|
97a9312be8 | ||
|
427cede4ba | ||
|
7371663aeb | ||
|
fe53edd776 | ||
|
4f6a7ad5f8 | ||
|
55a9229922 | ||
|
7802ccc8d6 | ||
|
3ff5151661 | ||
|
5936a9c23e | ||
|
9ffaba7c1b | ||
|
535ede2598 | ||
|
6ccdaa243f | ||
|
ace0b946ff | ||
|
a34036c296 | ||
|
9fec391d6e | ||
|
a835fa85d7 | ||
|
2c66c15227 | ||
|
92a73cd637 | ||
|
6e2795bfbf | ||
|
276b595361 | ||
|
3c293b418b | ||
|
41425e9b85 | ||
|
31682a3274 | ||
|
870f94b493 | ||
|
242e9ada91 | ||
|
9b444fd417 | ||
|
e9473f610e | ||
|
53002b3a00 | ||
|
a098b65252 | ||
|
78b0055e5e | ||
|
648bec3982 | ||
|
c2a8f59560 | ||
|
38404969df | ||
|
19c430feba | ||
|
3ba409558e | ||
|
60be627557 | ||
|
8cfe7df3f1 | ||
|
ba94b6d7be | ||
|
30e01355f6 | ||
|
06624e13d4 | ||
|
19539866e5 | ||
|
1dc2dcebbf | ||
|
6049a63d1d | ||
|
3ef8e76534 | ||
|
fbf07f3f69 | ||
|
de133113a0 | ||
|
6d0a59a1bf | ||
|
2491401932 | ||
|
fbbe8f2f98 | ||
|
71d42e778a | ||
|
8a2a1b22fe | ||
|
a790f0c082 | ||
|
0ab152b2c6 | ||
|
2741d6bb0e | ||
|
74d0e5c318 | ||
|
c4ef4a21c6 | ||
|
ee2f33bf9a | ||
|
531470a0ca | ||
|
9dc73593a3 | ||
|
ae6858bddf | ||
|
99d4d368e8 | ||
|
8667d5169d | ||
|
1add5a53cb | ||
|
729bf3e45a | ||
|
2f34b53b5b | ||
|
ad79f9eb99 | ||
|
9e494e67c7 | ||
|
5322473d04 | ||
|
c57ad7ff9a | ||
|
c59b5c533d | ||
|
0653cc8a7c | ||
|
246233d0d4 | ||
|
a910a81b7c | ||
|
c8acee2234 | ||
|
55863e42c1 | ||
|
6177cae2a2 | ||
|
6af3ccf65d | ||
|
03cb5f3397 | ||
|
113141d4f9 | ||
|
993ea6be7a | ||
|
889fe7f203 | ||
|
efd09d0b77 | ||
|
ffbc618a13 | ||
|
563ffc51b5 | ||
|
51b42ff2e1 | ||
|
7a755be4c2 | ||
|
06ea49159e | ||
|
869b21c869 | ||
|
37a808c5a5 | ||
|
24b8c0ce92 | ||
|
fe67e094ad | ||
|
fbcf39976e | ||
|
4863591c23 | ||
|
827da2c867 | ||
|
efe1571b7b | ||
|
6521fc0695 | ||
|
f5531845bc | ||
|
13fae78b32 | ||
|
b7d395d83a | ||
|
6fbbeec064 | ||
|
0ffa3bdc45 | ||
|
ca8639dc05 | ||
|
8d6a193c1a | ||
|
58a1ba85c7 | ||
|
b0c05aa3a9 | ||
|
0996a1e4ae | ||
|
7e9ddc9904 | ||
|
04bbb9de3e | ||
|
bea56788cb | ||
|
48bcc2ee12 | ||
|
080935a8c7 | ||
|
a466f57007 | ||
|
41f77d8018 | ||
|
e674345e29 | ||
|
3f8139c55f | ||
|
98c09b3f30 | ||
|
7462b95829 | ||
|
7a64182f9a | ||
|
d19de2ee80 | ||
|
08eb9352ab | ||
|
0b79d21c7f | ||
|
bce5f29265 | ||
|
3d5a2dd19f | ||
|
7f90ddb519 | ||
|
c66ab2c4c3 | ||
|
f53796c1fe | ||
|
14b27a8893 | ||
|
21be42abed | ||
|
2d681fd84c | ||
|
c39b1bffec | ||
|
62612e8575 | ||
|
af932ce3bc | ||
|
265b0a8045 | ||
|
74390c521e | ||
|
abfb858f0c | ||
|
6500d72aaf | ||
|
d6877eb8f9 | ||
|
ebb9bf3f12 | ||
|
61cf9bb5f1 | ||
|
a7152e055a | ||
|
63866009e2 | ||
|
dab89af070 | ||
|
eebbf2b1fc | ||
|
e885bc5c24 | ||
|
173dc129fc | ||
|
3abced8d64 | ||
|
a48ff4a738 | ||
|
6c92f9d83e | ||
|
9852e22101 | ||
|
b141cccbfb | ||
|
ec45068972 | ||
|
832bcdf631 | ||
|
73f9c02f49 | ||
|
6a25a61142 | ||
|
1dbbed169a | ||
|
a8f27abe12 | ||
|
ca2aec0235 | ||
|
e827831514 | ||
|
923d60bb12 | ||
|
f2bf8dc8c8 | ||
|
055ded74de | ||
|
3ff71284fa | ||
|
cc0b97e197 | ||
|
8c69e29820 | ||
|
843d9038ce | ||
|
d071a30238 | ||
|
3ab8ca4d84 | ||
|
23f4048b57 | ||
|
401b740ccd | ||
|
a468b0f57f | ||
|
b0cfa7272e | ||
|
683e05f60b | ||
|
16b637bf1b | ||
|
2698540c1e | ||
|
d2f5e69d3e | ||
|
ce64f18587 | ||
|
667fa59b0c | ||
|
5a6220f43b | ||
|
7c6dd3c2c3 | ||
|
740af6ed44 | ||
|
782d607962 | ||
|
50e52e45f9 | ||
|
a2d10216ea | ||
|
f54eb96338 | ||
|
a2b1c5e6f6 | ||
|
c5c1430a1c | ||
|
f7de9aea7b | ||
|
199c5e965e | ||
|
06a49fc04b | ||
|
6349bd422a | ||
|
796a4a1325 | ||
|
2cf6652ba2 | ||
|
9b508f6b53 | ||
|
6e26c70f46 | ||
|
9a34592c09 | ||
|
7eb6f2cb56 | ||
|
83fd8a5692 | ||
|
17058484d1 | ||
|
166077ea48 | ||
|
0c6c3c1da6 | ||
|
fe9a1fe03b | ||
|
1e4a34d45e | ||
|
189f29e939 | ||
|
d2ce444008 | ||
|
ef9420adf5 | ||
|
cb96e05a91 | ||
|
f6387dc766 | ||
|
1b1d7ed98f | ||
|
df7d97e4b4 | ||
|
85978dadab | ||
|
9aaaab6b3b | ||
|
c1ad553d86 | ||
|
c1bf4694e7 | ||
|
1442c5a99e | ||
|
dac2ca7e21 | ||
|
375252279c | ||
|
295570c631 | ||
|
a93c6e9263 | ||
|
30907dc9d8 | ||
|
14f8a08f44 | ||
|
c63f15a9a7 | ||
|
ca538fc5eb | ||
|
6be2c49538 | ||
|
91088c305f | ||
|
900cd6518a | ||
|
fa810e8ccd | ||
|
497611ae84 | ||
|
2b89617aad | ||
|
b542b0457b | ||
|
120568651a | ||
|
f1d301a9a6 | ||
|
c9a6280c94 | ||
|
b5583cde41 | ||
|
6c1cd63a57 | ||
|
0d7ba56f5c | ||
|
3ac604e3ad | ||
|
9fb8ddf00e | ||
|
182ca3bad4 | ||
|
f027f17dcb | ||
|
ac772d8b0c | ||
|
9d9f44ac71 | ||
|
84274e4e9b | ||
|
c5479fe086 | ||
|
538d2c53d9 | ||
|
8de58e79b8 | ||
|
5e8d7995d1 | ||
|
3239f6212e | ||
|
209eb9f103 | ||
|
ef6304e4a1 | ||
|
21cdbfc196 | ||
|
fc8067348b | ||
|
9f11dc5616 | ||
|
ca0818c760 | ||
|
c12bfb7ffc | ||
|
228e591589 | ||
|
58128258b0 | ||
|
e7ae69a7be | ||
|
7e37ce6008 | ||
|
dbe09dd515 | ||
|
217d31d62f | ||
|
47642f245d | ||
|
cb760bdebe | ||
|
e3f8bca424 | ||
|
9fc8a02196 | ||
|
e36b775eae | ||
|
622dd61764 | ||
|
e81c1176aa | ||
|
ed0c1aa9d5 | ||
|
ac69ea9cdf | ||
|
0a40379214 | ||
|
72bc8da537 | ||
|
c3132fd508 | ||
|
96c3107daf | ||
|
ad21a0e166 | ||
|
32d15cc8ba | ||
|
1fd50e5306 | ||
|
6802374574 | ||
|
82c1d1eb20 | ||
|
5a5169e15c | ||
|
7c0b70a94e | ||
|
ca6a8495e1 | ||
|
c0a2196f91 | ||
|
da026abc27 | ||
|
27780313ac | ||
|
e5ed946bdb | ||
|
c319b79baa | ||
|
2818db8b33 | ||
|
0415de74b8 | ||
|
4075b8805d | ||
|
8ab3fbbaf2 | ||
|
cc39218dce | ||
|
8dbc9ed408 | ||
|
ba25eab0fa | ||
|
aa823bf24b | ||
|
a714abfc91 | ||
|
9270e91c09 | ||
|
b7974e2fa4 | ||
|
1e174875bf | ||
|
c26b665c0c | ||
|
0479b2a15f | ||
|
ff6606cacb | ||
|
407b1f186d | ||
|
de2a4d7c22 | ||
|
48aff62341 | ||
|
852ba86949 | ||
|
662fa421c6 | ||
|
d14163e74f | ||
|
11b4810142 | ||
|
9ecceb651b | ||
|
426a9d9103 | ||
|
17bf603222 | ||
|
bcd52e5724 | ||
|
956242dcec | ||
|
e686675f7d | ||
|
4ca0b0d1fa | ||
|
efd645e5a8 | ||
|
f0504e86b3 | ||
|
e28b673fba | ||
|
a77eade744 | ||
|
6531726a02 | ||
|
31b4729f27 | ||
|
a729db62a9 | ||
|
5336f57f05 | ||
|
eb72ff058f | ||
|
8a91d2c04e | ||
|
55e0dcf254 | ||
|
23e7bf1c00 | ||
|
10d487e13f | ||
|
40f5033cf9 | ||
|
b1bb1fa187 | ||
|
1d121483f6 | ||
|
124441af1f | ||
|
b861db97ea | ||
|
08e07046f9 | ||
|
a5e0cf09a6 | ||
|
f2388eab71 | ||
|
120865833c | ||
|
e6d8e91b3a | ||
|
475f868b7f | ||
|
0063ca2fb0 | ||
|
610fda6108 | ||
|
352eed09ae | ||
|
0a89e92a5e | ||
|
dde80f3f61 | ||
|
9a7ccc3746 | ||
|
910189d0a1 | ||
|
8482e8374c | ||
|
fee4fa9492 | ||
|
4dba769577 | ||
|
da895b1151 | ||
|
a74c0ea2db | ||
|
6a26c16eb0 | ||
|
af8e00ffe8 | ||
|
6931f9a7a4 | ||
|
544448abea | ||
|
e547bdd1ce | ||
|
d1562a7766 | ||
|
304b3eb328 | ||
|
9cd5233609 | ||
|
35a382968c | ||
|
7066af825a | ||
|
acc10353fe | ||
|
bca0ef6cd9 | ||
|
cede2a4b7c | ||
|
337209a6ea | ||
|
56e0443e1c | ||
|
b1a1b4000e | ||
|
8838c62fe9 |
563
.clang-format
Normal file
563
.clang-format
Normal file
@@ -0,0 +1,563 @@
|
||||
# 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
|
||||
|
||||
# Taken from:
|
||||
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
|
||||
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
|
||||
# | sort | uniq
|
||||
ForEachMacros:
|
||||
- 'apei_estatus_for_each_section'
|
||||
- 'ata_for_each_dev'
|
||||
- 'ata_for_each_link'
|
||||
- '__ata_qc_for_each'
|
||||
- 'ata_qc_for_each'
|
||||
- 'ata_qc_for_each_raw'
|
||||
- 'ata_qc_for_each_with_internal'
|
||||
- 'ax25_for_each'
|
||||
- 'ax25_uid_for_each'
|
||||
- '__bio_for_each_bvec'
|
||||
- 'bio_for_each_bvec'
|
||||
- 'bio_for_each_bvec_all'
|
||||
- 'bio_for_each_integrity_vec'
|
||||
- '__bio_for_each_segment'
|
||||
- 'bio_for_each_segment'
|
||||
- 'bio_for_each_segment_all'
|
||||
- 'bio_list_for_each'
|
||||
- 'bip_for_each_vec'
|
||||
- 'bitmap_for_each_clear_region'
|
||||
- 'bitmap_for_each_set_region'
|
||||
- 'blkg_for_each_descendant_post'
|
||||
- 'blkg_for_each_descendant_pre'
|
||||
- 'blk_queue_for_each_rl'
|
||||
- 'bond_for_each_slave'
|
||||
- 'bond_for_each_slave_rcu'
|
||||
- 'bpf_for_each_spilled_reg'
|
||||
- 'btree_for_each_safe128'
|
||||
- 'btree_for_each_safe32'
|
||||
- 'btree_for_each_safe64'
|
||||
- 'btree_for_each_safel'
|
||||
- 'card_for_each_dev'
|
||||
- 'cgroup_taskset_for_each'
|
||||
- 'cgroup_taskset_for_each_leader'
|
||||
- 'cpufreq_for_each_entry'
|
||||
- 'cpufreq_for_each_entry_idx'
|
||||
- 'cpufreq_for_each_valid_entry'
|
||||
- 'cpufreq_for_each_valid_entry_idx'
|
||||
- 'css_for_each_child'
|
||||
- 'css_for_each_descendant_post'
|
||||
- 'css_for_each_descendant_pre'
|
||||
- 'device_for_each_child_node'
|
||||
- 'displayid_iter_for_each'
|
||||
- 'dma_fence_chain_for_each'
|
||||
- 'do_for_each_ftrace_op'
|
||||
- 'drm_atomic_crtc_for_each_plane'
|
||||
- 'drm_atomic_crtc_state_for_each_plane'
|
||||
- 'drm_atomic_crtc_state_for_each_plane_state'
|
||||
- 'drm_atomic_for_each_plane_damage'
|
||||
- 'drm_client_for_each_connector_iter'
|
||||
- 'drm_client_for_each_modeset'
|
||||
- 'drm_connector_for_each_possible_encoder'
|
||||
- 'drm_for_each_bridge_in_chain'
|
||||
- 'drm_for_each_connector_iter'
|
||||
- 'drm_for_each_crtc'
|
||||
- 'drm_for_each_crtc_reverse'
|
||||
- 'drm_for_each_encoder'
|
||||
- 'drm_for_each_encoder_mask'
|
||||
- 'drm_for_each_fb'
|
||||
- 'drm_for_each_legacy_plane'
|
||||
- 'drm_for_each_plane'
|
||||
- 'drm_for_each_plane_mask'
|
||||
- 'drm_for_each_privobj'
|
||||
- 'drm_mm_for_each_hole'
|
||||
- 'drm_mm_for_each_node'
|
||||
- 'drm_mm_for_each_node_in_range'
|
||||
- 'drm_mm_for_each_node_safe'
|
||||
- 'flow_action_for_each'
|
||||
- 'for_each_acpi_dev_match'
|
||||
- 'for_each_active_dev_scope'
|
||||
- 'for_each_active_drhd_unit'
|
||||
- 'for_each_active_iommu'
|
||||
- 'for_each_aggr_pgid'
|
||||
- 'for_each_available_child_of_node'
|
||||
- 'for_each_bio'
|
||||
- 'for_each_board_func_rsrc'
|
||||
- 'for_each_bvec'
|
||||
- 'for_each_card_auxs'
|
||||
- 'for_each_card_auxs_safe'
|
||||
- 'for_each_card_components'
|
||||
- 'for_each_card_dapms'
|
||||
- 'for_each_card_pre_auxs'
|
||||
- 'for_each_card_prelinks'
|
||||
- 'for_each_card_rtds'
|
||||
- 'for_each_card_rtds_safe'
|
||||
- 'for_each_card_widgets'
|
||||
- 'for_each_card_widgets_safe'
|
||||
- 'for_each_cgroup_storage_type'
|
||||
- 'for_each_child_of_node'
|
||||
- 'for_each_clear_bit'
|
||||
- 'for_each_clear_bit_from'
|
||||
- 'for_each_cmsghdr'
|
||||
- 'for_each_compatible_node'
|
||||
- 'for_each_component_dais'
|
||||
- 'for_each_component_dais_safe'
|
||||
- 'for_each_comp_order'
|
||||
- 'for_each_console'
|
||||
- 'for_each_cpu'
|
||||
- 'for_each_cpu_and'
|
||||
- 'for_each_cpu_not'
|
||||
- 'for_each_cpu_wrap'
|
||||
- 'for_each_dapm_widgets'
|
||||
- 'for_each_dev_addr'
|
||||
- 'for_each_dev_scope'
|
||||
- 'for_each_dma_cap_mask'
|
||||
- 'for_each_dpcm_be'
|
||||
- 'for_each_dpcm_be_rollback'
|
||||
- 'for_each_dpcm_be_safe'
|
||||
- 'for_each_dpcm_fe'
|
||||
- 'for_each_drhd_unit'
|
||||
- 'for_each_dss_dev'
|
||||
- 'for_each_dtpm_table'
|
||||
- 'for_each_efi_memory_desc'
|
||||
- 'for_each_efi_memory_desc_in_map'
|
||||
- 'for_each_element'
|
||||
- 'for_each_element_extid'
|
||||
- 'for_each_element_id'
|
||||
- 'for_each_endpoint_of_node'
|
||||
- 'for_each_evictable_lru'
|
||||
- 'for_each_fib6_node_rt_rcu'
|
||||
- 'for_each_fib6_walker_rt'
|
||||
- 'for_each_free_mem_pfn_range_in_zone'
|
||||
- 'for_each_free_mem_pfn_range_in_zone_from'
|
||||
- 'for_each_free_mem_range'
|
||||
- 'for_each_free_mem_range_reverse'
|
||||
- 'for_each_func_rsrc'
|
||||
- 'for_each_hstate'
|
||||
- 'for_each_if'
|
||||
- 'for_each_iommu'
|
||||
- 'for_each_ip_tunnel_rcu'
|
||||
- 'for_each_irq_nr'
|
||||
- 'for_each_link_codecs'
|
||||
- 'for_each_link_cpus'
|
||||
- 'for_each_link_platforms'
|
||||
- 'for_each_lru'
|
||||
- 'for_each_matching_node'
|
||||
- 'for_each_matching_node_and_match'
|
||||
- 'for_each_member'
|
||||
- 'for_each_memcg_cache_index'
|
||||
- 'for_each_mem_pfn_range'
|
||||
- '__for_each_mem_range'
|
||||
- 'for_each_mem_range'
|
||||
- '__for_each_mem_range_rev'
|
||||
- 'for_each_mem_range_rev'
|
||||
- 'for_each_mem_region'
|
||||
- 'for_each_migratetype_order'
|
||||
- 'for_each_msi_entry'
|
||||
- 'for_each_msi_entry_safe'
|
||||
- 'for_each_msi_vector'
|
||||
- 'for_each_net'
|
||||
- 'for_each_net_continue_reverse'
|
||||
- 'for_each_netdev'
|
||||
- 'for_each_netdev_continue'
|
||||
- 'for_each_netdev_continue_rcu'
|
||||
- 'for_each_netdev_continue_reverse'
|
||||
- 'for_each_netdev_feature'
|
||||
- 'for_each_netdev_in_bond_rcu'
|
||||
- 'for_each_netdev_rcu'
|
||||
- 'for_each_netdev_reverse'
|
||||
- 'for_each_netdev_safe'
|
||||
- 'for_each_net_rcu'
|
||||
- 'for_each_new_connector_in_state'
|
||||
- 'for_each_new_crtc_in_state'
|
||||
- 'for_each_new_mst_mgr_in_state'
|
||||
- 'for_each_new_plane_in_state'
|
||||
- 'for_each_new_private_obj_in_state'
|
||||
- 'for_each_node'
|
||||
- 'for_each_node_by_name'
|
||||
- 'for_each_node_by_type'
|
||||
- 'for_each_node_mask'
|
||||
- 'for_each_node_state'
|
||||
- 'for_each_node_with_cpus'
|
||||
- 'for_each_node_with_property'
|
||||
- 'for_each_nonreserved_multicast_dest_pgid'
|
||||
- 'for_each_of_allnodes'
|
||||
- 'for_each_of_allnodes_from'
|
||||
- 'for_each_of_cpu_node'
|
||||
- 'for_each_of_pci_range'
|
||||
- 'for_each_old_connector_in_state'
|
||||
- 'for_each_old_crtc_in_state'
|
||||
- 'for_each_old_mst_mgr_in_state'
|
||||
- 'for_each_oldnew_connector_in_state'
|
||||
- 'for_each_oldnew_crtc_in_state'
|
||||
- 'for_each_oldnew_mst_mgr_in_state'
|
||||
- 'for_each_oldnew_plane_in_state'
|
||||
- 'for_each_oldnew_plane_in_state_reverse'
|
||||
- 'for_each_oldnew_private_obj_in_state'
|
||||
- 'for_each_old_plane_in_state'
|
||||
- 'for_each_old_private_obj_in_state'
|
||||
- 'for_each_online_cpu'
|
||||
- 'for_each_online_node'
|
||||
- 'for_each_online_pgdat'
|
||||
- 'for_each_pci_bridge'
|
||||
- 'for_each_pci_dev'
|
||||
- 'for_each_pci_msi_entry'
|
||||
- 'for_each_pcm_streams'
|
||||
- 'for_each_physmem_range'
|
||||
- 'for_each_populated_zone'
|
||||
- 'for_each_possible_cpu'
|
||||
- 'for_each_present_cpu'
|
||||
- 'for_each_prime_number'
|
||||
- 'for_each_prime_number_from'
|
||||
- 'for_each_process'
|
||||
- 'for_each_process_thread'
|
||||
- 'for_each_prop_codec_conf'
|
||||
- 'for_each_prop_dai_codec'
|
||||
- 'for_each_prop_dai_cpu'
|
||||
- 'for_each_prop_dlc_codecs'
|
||||
- 'for_each_prop_dlc_cpus'
|
||||
- 'for_each_prop_dlc_platforms'
|
||||
- 'for_each_property_of_node'
|
||||
- 'for_each_registered_fb'
|
||||
- 'for_each_requested_gpio'
|
||||
- 'for_each_requested_gpio_in_range'
|
||||
- 'for_each_reserved_mem_range'
|
||||
- 'for_each_reserved_mem_region'
|
||||
- 'for_each_rtd_codec_dais'
|
||||
- 'for_each_rtd_components'
|
||||
- 'for_each_rtd_cpu_dais'
|
||||
- 'for_each_rtd_dais'
|
||||
- 'for_each_set_bit'
|
||||
- 'for_each_set_bit_from'
|
||||
- 'for_each_set_clump8'
|
||||
- 'for_each_sg'
|
||||
- 'for_each_sg_dma_page'
|
||||
- 'for_each_sg_page'
|
||||
- 'for_each_sgtable_dma_page'
|
||||
- 'for_each_sgtable_dma_sg'
|
||||
- 'for_each_sgtable_page'
|
||||
- 'for_each_sgtable_sg'
|
||||
- 'for_each_sibling_event'
|
||||
- 'for_each_subelement'
|
||||
- 'for_each_subelement_extid'
|
||||
- 'for_each_subelement_id'
|
||||
- '__for_each_thread'
|
||||
- 'for_each_thread'
|
||||
- 'for_each_unicast_dest_pgid'
|
||||
- 'for_each_vsi'
|
||||
- 'for_each_wakeup_source'
|
||||
- 'for_each_zone'
|
||||
- 'for_each_zone_zonelist'
|
||||
- 'for_each_zone_zonelist_nodemask'
|
||||
- 'fwnode_for_each_available_child_node'
|
||||
- 'fwnode_for_each_child_node'
|
||||
- 'fwnode_graph_for_each_endpoint'
|
||||
- 'gadget_for_each_ep'
|
||||
- 'genradix_for_each'
|
||||
- 'genradix_for_each_from'
|
||||
- 'hash_for_each'
|
||||
- 'hash_for_each_possible'
|
||||
- 'hash_for_each_possible_rcu'
|
||||
- 'hash_for_each_possible_rcu_notrace'
|
||||
- 'hash_for_each_possible_safe'
|
||||
- 'hash_for_each_rcu'
|
||||
- 'hash_for_each_safe'
|
||||
- 'hctx_for_each_ctx'
|
||||
- 'hlist_bl_for_each_entry'
|
||||
- 'hlist_bl_for_each_entry_rcu'
|
||||
- 'hlist_bl_for_each_entry_safe'
|
||||
- 'hlist_for_each'
|
||||
- 'hlist_for_each_entry'
|
||||
- 'hlist_for_each_entry_continue'
|
||||
- 'hlist_for_each_entry_continue_rcu'
|
||||
- 'hlist_for_each_entry_continue_rcu_bh'
|
||||
- 'hlist_for_each_entry_from'
|
||||
- 'hlist_for_each_entry_from_rcu'
|
||||
- 'hlist_for_each_entry_rcu'
|
||||
- 'hlist_for_each_entry_rcu_bh'
|
||||
- 'hlist_for_each_entry_rcu_notrace'
|
||||
- 'hlist_for_each_entry_safe'
|
||||
- 'hlist_for_each_entry_srcu'
|
||||
- '__hlist_for_each_rcu'
|
||||
- 'hlist_for_each_safe'
|
||||
- 'hlist_nulls_for_each_entry'
|
||||
- 'hlist_nulls_for_each_entry_from'
|
||||
- 'hlist_nulls_for_each_entry_rcu'
|
||||
- 'hlist_nulls_for_each_entry_safe'
|
||||
- 'i3c_bus_for_each_i2cdev'
|
||||
- 'i3c_bus_for_each_i3cdev'
|
||||
- 'ide_host_for_each_port'
|
||||
- 'ide_port_for_each_dev'
|
||||
- 'ide_port_for_each_present_dev'
|
||||
- 'idr_for_each_entry'
|
||||
- 'idr_for_each_entry_continue'
|
||||
- 'idr_for_each_entry_continue_ul'
|
||||
- 'idr_for_each_entry_ul'
|
||||
- 'in_dev_for_each_ifa_rcu'
|
||||
- 'in_dev_for_each_ifa_rtnl'
|
||||
- 'inet_bind_bucket_for_each'
|
||||
- 'inet_lhash2_for_each_icsk_rcu'
|
||||
- 'key_for_each'
|
||||
- 'key_for_each_safe'
|
||||
- 'klp_for_each_func'
|
||||
- 'klp_for_each_func_safe'
|
||||
- 'klp_for_each_func_static'
|
||||
- 'klp_for_each_object'
|
||||
- 'klp_for_each_object_safe'
|
||||
- 'klp_for_each_object_static'
|
||||
- 'kunit_suite_for_each_test_case'
|
||||
- 'kvm_for_each_memslot'
|
||||
- 'kvm_for_each_vcpu'
|
||||
- 'list_for_each'
|
||||
- 'list_for_each_codec'
|
||||
- 'list_for_each_codec_safe'
|
||||
- 'list_for_each_continue'
|
||||
- 'list_for_each_entry'
|
||||
- 'list_for_each_entry_continue'
|
||||
- 'list_for_each_entry_continue_rcu'
|
||||
- 'list_for_each_entry_continue_reverse'
|
||||
- 'list_for_each_entry_from'
|
||||
- 'list_for_each_entry_from_rcu'
|
||||
- 'list_for_each_entry_from_reverse'
|
||||
- 'list_for_each_entry_lockless'
|
||||
- 'list_for_each_entry_rcu'
|
||||
- 'list_for_each_entry_reverse'
|
||||
- 'list_for_each_entry_safe'
|
||||
- 'list_for_each_entry_safe_continue'
|
||||
- 'list_for_each_entry_safe_from'
|
||||
- 'list_for_each_entry_safe_reverse'
|
||||
- 'list_for_each_entry_srcu'
|
||||
- 'list_for_each_prev'
|
||||
- 'list_for_each_prev_safe'
|
||||
- 'list_for_each_safe'
|
||||
- 'llist_for_each'
|
||||
- 'llist_for_each_entry'
|
||||
- 'llist_for_each_entry_safe'
|
||||
- 'llist_for_each_safe'
|
||||
- 'mci_for_each_dimm'
|
||||
- 'media_device_for_each_entity'
|
||||
- 'media_device_for_each_intf'
|
||||
- 'media_device_for_each_link'
|
||||
- 'media_device_for_each_pad'
|
||||
- 'nanddev_io_for_each_page'
|
||||
- 'netdev_for_each_lower_dev'
|
||||
- 'netdev_for_each_lower_private'
|
||||
- 'netdev_for_each_lower_private_rcu'
|
||||
- 'netdev_for_each_mc_addr'
|
||||
- 'netdev_for_each_uc_addr'
|
||||
- 'netdev_for_each_upper_dev_rcu'
|
||||
- 'netdev_hw_addr_list_for_each'
|
||||
- 'nft_rule_for_each_expr'
|
||||
- 'nla_for_each_attr'
|
||||
- 'nla_for_each_nested'
|
||||
- 'nlmsg_for_each_attr'
|
||||
- 'nlmsg_for_each_msg'
|
||||
- 'nr_neigh_for_each'
|
||||
- 'nr_neigh_for_each_safe'
|
||||
- 'nr_node_for_each'
|
||||
- 'nr_node_for_each_safe'
|
||||
- 'of_for_each_phandle'
|
||||
- 'of_property_for_each_string'
|
||||
- 'of_property_for_each_u32'
|
||||
- 'pci_bus_for_each_resource'
|
||||
- 'pcl_for_each_chunk'
|
||||
- 'pcl_for_each_segment'
|
||||
- 'pcm_for_each_format'
|
||||
- 'ping_portaddr_for_each_entry'
|
||||
- 'plist_for_each'
|
||||
- 'plist_for_each_continue'
|
||||
- 'plist_for_each_entry'
|
||||
- 'plist_for_each_entry_continue'
|
||||
- 'plist_for_each_entry_safe'
|
||||
- 'plist_for_each_safe'
|
||||
- 'pnp_for_each_card'
|
||||
- 'pnp_for_each_dev'
|
||||
- 'protocol_for_each_card'
|
||||
- 'protocol_for_each_dev'
|
||||
- 'queue_for_each_hw_ctx'
|
||||
- 'radix_tree_for_each_slot'
|
||||
- 'radix_tree_for_each_tagged'
|
||||
- 'rb_for_each'
|
||||
- 'rbtree_postorder_for_each_entry_safe'
|
||||
- 'rdma_for_each_block'
|
||||
- 'rdma_for_each_port'
|
||||
- 'rdma_umem_for_each_dma_block'
|
||||
- 'resource_list_for_each_entry'
|
||||
- 'resource_list_for_each_entry_safe'
|
||||
- 'rhl_for_each_entry_rcu'
|
||||
- 'rhl_for_each_rcu'
|
||||
- 'rht_for_each'
|
||||
- 'rht_for_each_entry'
|
||||
- 'rht_for_each_entry_from'
|
||||
- 'rht_for_each_entry_rcu'
|
||||
- 'rht_for_each_entry_rcu_from'
|
||||
- 'rht_for_each_entry_safe'
|
||||
- 'rht_for_each_from'
|
||||
- 'rht_for_each_rcu'
|
||||
- 'rht_for_each_rcu_from'
|
||||
- '__rq_for_each_bio'
|
||||
- 'rq_for_each_bvec'
|
||||
- 'rq_for_each_segment'
|
||||
- 'scsi_for_each_prot_sg'
|
||||
- 'scsi_for_each_sg'
|
||||
- 'sctp_for_each_hentry'
|
||||
- 'sctp_skb_for_each'
|
||||
- 'shdma_for_each_chan'
|
||||
- '__shost_for_each_device'
|
||||
- 'shost_for_each_device'
|
||||
- 'sk_for_each'
|
||||
- 'sk_for_each_bound'
|
||||
- 'sk_for_each_entry_offset_rcu'
|
||||
- 'sk_for_each_from'
|
||||
- 'sk_for_each_rcu'
|
||||
- 'sk_for_each_safe'
|
||||
- 'sk_nulls_for_each'
|
||||
- 'sk_nulls_for_each_from'
|
||||
- 'sk_nulls_for_each_rcu'
|
||||
- 'snd_array_for_each'
|
||||
- 'snd_pcm_group_for_each_entry'
|
||||
- 'snd_soc_dapm_widget_for_each_path'
|
||||
- 'snd_soc_dapm_widget_for_each_path_safe'
|
||||
- 'snd_soc_dapm_widget_for_each_sink_path'
|
||||
- 'snd_soc_dapm_widget_for_each_source_path'
|
||||
- 'tb_property_for_each'
|
||||
- 'tcf_exts_for_each_action'
|
||||
- 'udp_portaddr_for_each_entry'
|
||||
- 'udp_portaddr_for_each_entry_rcu'
|
||||
- 'usb_hub_for_each_child'
|
||||
- 'v4l2_device_for_each_subdev'
|
||||
- 'v4l2_m2m_for_each_dst_buf'
|
||||
- 'v4l2_m2m_for_each_dst_buf_safe'
|
||||
- 'v4l2_m2m_for_each_src_buf'
|
||||
- 'v4l2_m2m_for_each_src_buf_safe'
|
||||
- 'virtio_device_for_each_vq'
|
||||
- 'while_for_each_ftrace_op'
|
||||
- 'xa_for_each'
|
||||
- 'xa_for_each_marked'
|
||||
- 'xa_for_each_range'
|
||||
- 'xa_for_each_start'
|
||||
- 'xas_for_each'
|
||||
- 'xas_for_each_conflict'
|
||||
- 'xas_for_each_marked'
|
||||
- 'xbc_array_for_each_value'
|
||||
- 'xbc_for_each_key_value'
|
||||
- 'xbc_node_for_each_array_value'
|
||||
- 'xbc_node_for_each_child'
|
||||
- 'xbc_node_for_each_key_value'
|
||||
- 'zorro_for_each_dev'
|
||||
- 'for_each_line'
|
||||
- 'for_each_non_empty_line'
|
||||
|
||||
#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
|
||||
...
|
58
.gitignore
vendored
58
.gitignore
vendored
@@ -2,26 +2,21 @@ debian/*.log
|
||||
*.o
|
||||
*.lo
|
||||
*.a
|
||||
*.la
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
bscconfig.h
|
||||
bscconfig.h.in
|
||||
openbsc.pc
|
||||
src/osmo-nitb/osmo-nitb
|
||||
src/osmo-bsc_mgcp/osmo-bsc_mgcp
|
||||
src/osmo-bsc/osmo-bsc
|
||||
src/utils/meas_vis
|
||||
src/utils/meas_json
|
||||
src/utils/osmo-meas-pcap2db
|
||||
src/utils/osmo-meas-udp2db
|
||||
src/utils/smpp_mirror
|
||||
src/osmo-mgw/osmo-mgw
|
||||
*.*~
|
||||
*.sw?
|
||||
.libs
|
||||
*.pyc
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.pc
|
||||
*~
|
||||
|
||||
#configure
|
||||
aclocal.m4
|
||||
@@ -38,38 +33,16 @@ missing
|
||||
stamp-h1
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4/*.m4
|
||||
|
||||
# git-version-gen magic
|
||||
.tarball-version
|
||||
.version
|
||||
|
||||
|
||||
# apps and app data
|
||||
hlr.sqlite3
|
||||
src/utils/bs11_config
|
||||
src/ipaccess/ipaccess-config
|
||||
src/ipaccess/abisip-find
|
||||
src/ipaccess/ipaccess-firmware
|
||||
src/ipaccess/ipaccess-proxy
|
||||
src/utils/isdnsync
|
||||
src/nat/bsc_nat
|
||||
src/gprs/osmo-sgsn
|
||||
src/gprs/osmo-gbproxy
|
||||
src/gprs/osmo-gtphub
|
||||
src/osmo-bsc_nat/osmo-bsc_nat
|
||||
src/libcommon/gsup_test_client
|
||||
src/osmo-msc/osmo-msc
|
||||
|
||||
#tests
|
||||
tests/testsuite.dir
|
||||
tests/*/*_test
|
||||
# ignore compiled binaries like msc_vlr_test_foo; do not ignore
|
||||
# msc_vlr_test_foo.{c,ok,err}, but do still ignore the corresponding .o object
|
||||
# files:
|
||||
tests/msc_vlr/msc_vlr_test_*
|
||||
!tests/msc_vlr/msc_vlr_test_*.*
|
||||
tests/msc_vlr/msc_vlr_test_*.o
|
||||
|
||||
|
||||
tests/atconfig
|
||||
tests/atlocal
|
||||
@@ -77,7 +50,22 @@ tests/package.m4
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
|
||||
gsn_restart
|
||||
src/openbsc.cfg*
|
||||
writtenconfig/
|
||||
gtphub_restart_count
|
||||
|
||||
# manuals
|
||||
doc/manuals/*.html
|
||||
doc/manuals/*.svg
|
||||
doc/manuals/*.pdf
|
||||
doc/manuals/*__*.png
|
||||
doc/manuals/*.check
|
||||
doc/manuals/generated/
|
||||
doc/manuals/osmomsc-usermanual.xml
|
||||
doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
contrib/osmo-mgw.spec
|
||||
|
||||
#vs code
|
||||
.cache
|
||||
.vscode
|
||||
|
||||
|
14
Makefile.am
14
Makefile.am
@@ -9,21 +9,29 @@ AM_CPPFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
SUBDIRS = \
|
||||
doc \
|
||||
include \
|
||||
src \
|
||||
tests \
|
||||
doc \
|
||||
contrib \
|
||||
$(NULL)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
libosmo-legacy-mgcp.pc \
|
||||
libosmo-mgcp-client.pc \
|
||||
$(NULL)
|
||||
|
||||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
EXTRA_DIST = git-version-gen osmoappdesc.py .version
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-mgw.spec.in \
|
||||
debian \
|
||||
git-version-gen \
|
||||
osmoappdesc.py \
|
||||
$(NULL)
|
||||
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||
|
||||
@RELMAKE@
|
||||
|
||||
|
4
README
4
README
@@ -19,10 +19,6 @@ 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.
|
||||
|
||||
The libosmo-mgcp library exposes MGCP server utilities used by e.g. OsmoBSC-NAT
|
||||
(found in osmo-bsc.git) to navigate RTP streams through a NAT.
|
||||
(At time of writing, this is still called libosmo-legacy-mgcp.)
|
||||
|
||||
Find OsmoMGW issue tracker and wiki online at
|
||||
https://osmocom.org/projects/osmo-mgw
|
||||
https://osmocom.org/projects/osmo-mgw/wiki
|
||||
|
@@ -24,3 +24,5 @@
|
||||
# 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()
|
||||
libosmo-mgcp-client struct mgcp_client_conf ABI breackage
|
131
configure.ac
131
configure.ac
@@ -9,6 +9,8 @@ AC_CONFIG_AUX_DIR([.])
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
|
||||
CFLAGS="$CFLAGS -std=gnu11"
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
@@ -22,6 +24,11 @@ AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
LT_INIT
|
||||
|
||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
||||
AS_CASE(["$LD"],[*clang*],
|
||||
[AS_CASE(["${host_os}"],
|
||||
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
|
||||
|
||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||
@@ -29,20 +36,24 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||
fi
|
||||
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
|
||||
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
|
||||
AC_SUBST(LIBRARY_DL)
|
||||
|
||||
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
|
||||
AC_SUBST(LIBRARY_DLSYM)
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.2.0)
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.1.0)
|
||||
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
|
||||
AC_ARG_ENABLE(sanitize,
|
||||
[AS_HELP_STRING(
|
||||
@@ -74,42 +85,6 @@ then
|
||||
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
|
||||
fi
|
||||
|
||||
# Enable/disable transcoding within osmo-bsc_mgcp?
|
||||
AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])],
|
||||
[osmo_ac_mgcp_transcoding="$enableval"],[osmo_ac_mgcp_transcoding="no"])
|
||||
AC_ARG_WITH([g729], [AS_HELP_STRING([--with-g729], [Enable G.729 encoding/decoding.])], [osmo_ac_with_g729="$withval"],[osmo_ac_with_g729="no"])
|
||||
|
||||
if test "$osmo_ac_mgcp_transcoding" = "yes" ; then
|
||||
AC_SEARCH_LIBS([gsm_create], [gsm], [LIBRARY_GSM="$LIBS";LIBS=""], [AC_MSG_ERROR([--enable-mgcp-transcoding: cannot find usable libgsm])])
|
||||
AC_SUBST(LIBRARY_GSM)
|
||||
if test "$osmo_ac_with_g729" = "yes" ; then
|
||||
PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 0.1, [AC_DEFINE([HAVE_BCG729], [1], [Use bgc729 decoder/encoder])])
|
||||
fi
|
||||
AC_DEFINE(BUILD_MGCP_TRANSCODING, 1, [Define if we want to build the MGCP gateway with transcoding support])
|
||||
fi
|
||||
AM_CONDITIONAL(BUILD_MGCP_TRANSCODING, test "x$osmo_ac_mgcp_transcoding" = "xyes")
|
||||
AC_SUBST(osmo_ac_mgcp_transcoding)
|
||||
|
||||
dnl Checks for typedefs, structures and compiler characteristics
|
||||
|
||||
# The following test is taken from WebKit's webkit.m4
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -fvisibility=hidden "
|
||||
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
|
||||
[ AC_MSG_RESULT([yes])
|
||||
SYMBOL_VISIBILITY="-fvisibility=hidden"],
|
||||
AC_MSG_RESULT([no]))
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
AC_SUBST(SYMBOL_VISIBILITY)
|
||||
|
||||
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([-Werror=null-dereference], [CFLAGS="$CFLAGS -Werror=null-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
|
||||
AC_MSG_CHECKING([whether to enable code coverage support])
|
||||
AC_ARG_ENABLE(coverage,
|
||||
@@ -144,6 +119,64 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
|
||||
AC_MSG_RESULT([$enable_ext_tests])
|
||||
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
|
||||
|
||||
# Generate manuals
|
||||
AC_ARG_ENABLE(manuals,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-manuals],
|
||||
[Generate manual PDFs [default=no]],
|
||||
)],
|
||||
[osmo_ac_build_manuals=$enableval], [osmo_ac_build_manuals="no"])
|
||||
AM_CONDITIONAL([BUILD_MANUALS], [test x"$osmo_ac_build_manuals" = x"yes"])
|
||||
AC_ARG_VAR(OSMO_GSM_MANUALS_DIR, [path to common osmo-gsm-manuals files, overriding pkg-config and "../osmo-gsm-manuals"
|
||||
fallback])
|
||||
if test x"$osmo_ac_build_manuals" = x"yes"
|
||||
then
|
||||
# Find OSMO_GSM_MANUALS_DIR (env, pkg-conf, fallback)
|
||||
if test -n "$OSMO_GSM_MANUALS_DIR"; then
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from env)"
|
||||
else
|
||||
OSMO_GSM_MANUALS_DIR="$($PKG_CONFIG osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)"
|
||||
if test -n "$OSMO_GSM_MANUALS_DIR"; then
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from pkg-conf)"
|
||||
else
|
||||
OSMO_GSM_MANUALS_DIR="../osmo-gsm-manuals"
|
||||
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (fallback)"
|
||||
fi
|
||||
fi
|
||||
if ! test -d "$OSMO_GSM_MANUALS_DIR"; then
|
||||
AC_MSG_ERROR("OSMO_GSM_MANUALS_DIR does not exist! Install osmo-gsm-manuals or set OSMO_GSM_MANUALS_DIR.")
|
||||
fi
|
||||
|
||||
# Find and run check-depends
|
||||
CHECK_DEPENDS="$OSMO_GSM_MANUALS_DIR/check-depends.sh"
|
||||
if ! test -x "$CHECK_DEPENDS"; then
|
||||
CHECK_DEPENDS="osmo-gsm-manuals-check-depends"
|
||||
fi
|
||||
if ! $CHECK_DEPENDS; then
|
||||
AC_MSG_ERROR("missing dependencies for --enable-manuals")
|
||||
fi
|
||||
|
||||
# Put in Makefile with absolute path
|
||||
OSMO_GSM_MANUALS_DIR="$(realpath "$OSMO_GSM_MANUALS_DIR")"
|
||||
AC_SUBST([OSMO_GSM_MANUALS_DIR])
|
||||
fi
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/daemon.html
|
||||
AC_ARG_WITH([systemdsystemunitdir],
|
||||
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
|
||||
[with_systemdsystemunitdir=auto])
|
||||
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
|
||||
def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
|
||||
|
||||
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
|
||||
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
|
||||
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
|
||||
with_systemdsystemunitdir=no],
|
||||
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
|
||||
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
|
||||
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
|
||||
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
|
||||
|
||||
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
|
||||
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
|
||||
|
||||
@@ -151,25 +184,23 @@ dnl Generate the output
|
||||
AM_CONFIG_HEADER(bscconfig.h)
|
||||
|
||||
AC_OUTPUT(
|
||||
libosmo-legacy-mgcp.pc
|
||||
libosmo-mgcp-client.pc
|
||||
include/Makefile
|
||||
include/osmocom/Makefile
|
||||
include/osmocom/legacy_mgcp/Makefile
|
||||
include/osmocom/mgcp_client/Makefile
|
||||
include/osmocom/mgcp/Makefile
|
||||
src/Makefile
|
||||
src/libosmo-legacy-mgcp/Makefile
|
||||
src/libosmo-mgcp-client/Makefile
|
||||
src/libosmo-mgcp/Makefile
|
||||
src/osmo-bsc_mgcp/Makefile
|
||||
src/osmo-mgw/Makefile
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
tests/legacy_mgcp/Makefile
|
||||
tests/mgcp_client/Makefile
|
||||
tests/mgcp/Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/osmo-mgw.spec
|
||||
Makefile)
|
||||
|
@@ -1 +1,3 @@
|
||||
SUBDIRS = systemd
|
||||
|
||||
EXTRA_DIST = ipa.py
|
||||
|
@@ -1,5 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# jenkins build helper script for openbsc. This is how we build on jenkins.osmocom.org
|
||||
#
|
||||
# environment variables:
|
||||
# * WITH_MANUALS: build manual PDFs if set to "1"
|
||||
# * PUBLISH: upload manuals after building if set to "1" (ignored without WITH_MANUALS = "1")
|
||||
#
|
||||
|
||||
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
|
||||
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
|
||||
@@ -23,10 +28,17 @@ verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
|
||||
|
||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export LD_LIBRARY_PATH="$inst/lib"
|
||||
export PATH="$inst/bin:$PATH"
|
||||
|
||||
osmo-build-dep.sh libosmo-abis
|
||||
osmo-build-dep.sh libosmo-netif
|
||||
|
||||
# Additional configure options and depends
|
||||
CONFIG=""
|
||||
if [ "$WITH_MANUALS" = "1" ]; then
|
||||
CONFIG="--enable-manuals"
|
||||
fi
|
||||
|
||||
set +x
|
||||
echo
|
||||
echo
|
||||
@@ -37,13 +49,18 @@ set -x
|
||||
|
||||
cd "$base"
|
||||
autoreconf --install --force
|
||||
./configure $MGCP --enable-vty-tests --enable-external-tests --enable-werror
|
||||
./configure --enable-sanitize --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
|
||||
$MAKE $PARALLEL_MAKE
|
||||
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|
||||
|| cat-testlogs.sh
|
||||
LD_LIBRARY_PATH="$inst/lib" \
|
||||
DISTCHECK_CONFIGURE_FLAGS="$MGCP --enable-vty-tests --enable-external-tests" \
|
||||
$MAKE distcheck \
|
||||
DISTCHECK_CONFIGURE_FLAGS="--enable-vty-tests --enable-external-tests $CONFIG" \
|
||||
$MAKE $PARALLEL_MAKE distcheck \
|
||||
|| cat-testlogs.sh
|
||||
|
||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
|
137
contrib/osmo-mgw.spec.in
Normal file
137
contrib/osmo-mgw.spec.in
Normal file
@@ -0,0 +1,137 @@
|
||||
#
|
||||
# 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
|
11
contrib/rtp-load-gen/Makefile
Normal file
11
contrib/rtp-load-gen/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
CFLAGS=-g -Wall $(shell pkg-config --cflags libosmocore libosmoctrl libosmo-netif liburing)
|
||||
LIBS=-lpthread $(shell pkg-config --libs libosmocore libosmoctrl libosmo-netif liburing)
|
||||
|
||||
rtp-load-gen: rtp-load-gen.o rtp_provider.o rtp_provider_static.o ctrl_if.o
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^
|
||||
|
||||
clean:
|
||||
@rm rtp-load-gen *.o
|
214
contrib/rtp-load-gen/ctrl_if.c
Normal file
214
contrib/rtp-load-gen/ctrl_if.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/* CTRL interface of rtpsource program
|
||||
*
|
||||
* (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 General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <osmocom/ctrl/control_cmd.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "rtp_provider.h"
|
||||
|
||||
static struct rtpsim_connection *find_connection_by_cname(const char *cname)
|
||||
{
|
||||
struct rtpsim_connection *rtpc;
|
||||
struct rtpsim_instance *ri;
|
||||
|
||||
pthread_rwlock_rdlock(&g_rtpsim->rwlock);
|
||||
llist_for_each_entry(ri, &g_rtpsim->instances, list) {
|
||||
rtpc = rtpsim_conn_find(ri, cname);
|
||||
if (rtpc) {
|
||||
pthread_rwlock_unlock(&g_rtpsim->rwlock);
|
||||
return rtpc;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&g_rtpsim->rwlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct rtpsim_connection *create_connection(const char *cname, enum codec_type codec)
|
||||
{
|
||||
struct rtpsim_connection *rtpc;
|
||||
struct rtpsim_instance *ri;
|
||||
|
||||
pthread_rwlock_rdlock(&g_rtpsim->rwlock);
|
||||
llist_for_each_entry(ri, &g_rtpsim->instances, list) {
|
||||
rtpc = rtpsim_conn_reserve(ri, cname, codec);
|
||||
if (rtpc) {
|
||||
pthread_rwlock_unlock(&g_rtpsim->rwlock);
|
||||
return rtpc;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&g_rtpsim->rwlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int connect_connection(struct rtpsim_connection *rtpc, const char *remote_host,
|
||||
uint16_t remote_port, uint8_t pt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
osmo_sockaddr_str_from_str(&rtpc->cfg.remote, remote_host, remote_port);
|
||||
rtpc->cfg.pt = pt;
|
||||
|
||||
rc = rtpsim_conn_connect(rtpc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = rtpsim_conn_start(rtpc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int delete_connection(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
rtpsim_conn_stop(rtpc);
|
||||
rtpsim_conn_unreserve(rtpc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(rtp_create, "rtp_create");
|
||||
static int set_rtp_create(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct rtpsim_connection *conn;
|
||||
const char *cname, *codec_str;
|
||||
char *tmp, *saveptr;
|
||||
enum codec_type codec;
|
||||
|
||||
tmp = talloc_strdup(cmd, cmd->value);
|
||||
OSMO_ASSERT(tmp);
|
||||
|
||||
cname = strtok_r(tmp, ",", &saveptr);
|
||||
codec_str = strtok_r(NULL, ",", &saveptr);
|
||||
|
||||
if (!cname || !codec_str) {
|
||||
cmd->reply = "Format is cname,codec";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (find_connection_by_cname(cname)) {
|
||||
cmd->reply = "Connection already exists for cname";
|
||||
goto error;
|
||||
}
|
||||
|
||||
codec = get_string_value(codec_type_names, codec_str);
|
||||
if (codec < 0) {
|
||||
cmd->reply = "Invalid codec name (try GSM_FR, GSM_EFR etc.)";
|
||||
goto error;
|
||||
}
|
||||
|
||||
conn = create_connection(cname, codec);
|
||||
if (!conn) {
|
||||
cmd->reply = "Error creating RTP connection";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Respond */
|
||||
cmd->reply = talloc_asprintf(cmd, "%s,%s,%d", conn->cname, conn->cfg.local.ip, conn->cfg.local.port);
|
||||
talloc_free(tmp);
|
||||
return CTRL_CMD_REPLY;
|
||||
|
||||
error:
|
||||
talloc_free(tmp);
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(rtp_connect, "rtp_connect");
|
||||
static int set_rtp_connect(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct rtpsim_connection *conn;
|
||||
const char *cname, *remote_host, *remote_port, *pt;
|
||||
char *tmp, *saveptr;
|
||||
int rc;
|
||||
|
||||
tmp = talloc_strdup(cmd, cmd->value);
|
||||
OSMO_ASSERT(tmp);
|
||||
|
||||
/* FIXME: parse command */
|
||||
cname = strtok_r(tmp, ",", &saveptr);
|
||||
remote_host = strtok_r(NULL, ",", &saveptr);
|
||||
remote_port = strtok_r(NULL, ",", &saveptr);
|
||||
pt = strtok_r(NULL, ",", &saveptr);
|
||||
|
||||
if (!cname || !remote_host || !remote_port || !pt) {
|
||||
cmd->reply = "Format is cname,remote_host,remote_port,pt";
|
||||
talloc_free(tmp);
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
conn = find_connection_by_cname(cname);
|
||||
if (!conn) {
|
||||
cmd->reply = "Error finding RTP connection for connect";
|
||||
talloc_free(tmp);
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
rc = connect_connection(conn, remote_host, atoi(remote_port), atoi(pt));
|
||||
if (rc < 0) {
|
||||
cmd->reply = "Error binding RTP connection";
|
||||
talloc_free(tmp);
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Respond */
|
||||
talloc_free(tmp);
|
||||
cmd->reply = talloc_asprintf(cmd, "%s,%s,%d,%d", conn->cname, conn->cfg.remote.ip,
|
||||
conn->cfg.remote.port, conn->cfg.pt);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(rtp_delete, "rtp_delete");
|
||||
static int set_rtp_delete(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct rtpsim_connection *conn;
|
||||
const char *cname = cmd->value;
|
||||
|
||||
conn = find_connection_by_cname(cname);
|
||||
if (!conn) {
|
||||
cmd->reply = "Error finding RTP connection for delete";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
cmd->reply = talloc_asprintf(cmd, "%s", conn->cname);
|
||||
|
||||
delete_connection(conn);
|
||||
|
||||
/* Respond */
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int rtpsource_ctrl_cmds_install(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_create);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_connect);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_delete);
|
||||
if (rc)
|
||||
goto end;
|
||||
end:
|
||||
return rc;
|
||||
}
|
112
contrib/rtp-load-gen/internal.h
Normal file
112
contrib/rtp-load-gen/internal.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include <liburing.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
|
||||
struct rtp_provider_instance;
|
||||
|
||||
/* configuration of one RTP connection/socket */
|
||||
struct rtpsim_connection_cfg {
|
||||
struct osmo_sockaddr_str local;
|
||||
struct osmo_sockaddr_str remote;
|
||||
uint8_t pt;
|
||||
uint32_t ssrc;
|
||||
uint32_t duration;
|
||||
};
|
||||
|
||||
/* TX side state of RTP connection/socket */
|
||||
struct rtpsim_connection_tx {
|
||||
bool enabled;
|
||||
uint32_t timestamp;
|
||||
uint16_t seq;
|
||||
|
||||
struct rtp_provider_instance *rtp_prov_inst;
|
||||
|
||||
/* transmit buffer for outgoing messages */
|
||||
uint8_t *buf;
|
||||
/* used part of buffer */
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
/* RX side state of RTP connection/socket */
|
||||
struct rtpsim_connection_rx {
|
||||
bool enabled;
|
||||
/* receive buffer for incoming messages */
|
||||
uint8_t *buf;
|
||||
/* used length of buffer */
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
struct rtpsim_instance;
|
||||
|
||||
/* One RTP connection/socket */
|
||||
struct rtpsim_connection {
|
||||
/* index in rtp_instance.connections */
|
||||
unsigned int idx;
|
||||
/* back-pointer */
|
||||
struct rtpsim_instance *inst;
|
||||
|
||||
struct rtpsim_connection_cfg cfg;
|
||||
struct rtpsim_connection_tx tx;
|
||||
struct rtpsim_connection_rx rx;
|
||||
struct rate_ctr_group *ctrg;
|
||||
|
||||
/* socket file descriptor */
|
||||
int fd;
|
||||
char *cname;
|
||||
};
|
||||
|
||||
struct rtpsim_instance_cfg {
|
||||
int num;
|
||||
uint16_t base_port;
|
||||
unsigned int num_flows;
|
||||
};
|
||||
|
||||
/* one instance of the RTP simulator; typically one per worker thread */
|
||||
struct rtpsim_instance {
|
||||
/* element in application global list of instances */
|
||||
struct llist_head list;
|
||||
struct rtpsim_instance_cfg cfg;
|
||||
/* per-instance io_uring */
|
||||
struct io_uring ring;
|
||||
/* per-instance timerfd */
|
||||
int timerfd;
|
||||
/* counter group of per-instance counters */
|
||||
struct rate_ctr_group *ctrg;
|
||||
|
||||
struct rtpsim_connection **connections;
|
||||
/* size of 'connections' in number of pointers */
|
||||
unsigned int connections_size;
|
||||
};
|
||||
|
||||
struct rtpsim_global {
|
||||
/* global list of instances */
|
||||
struct llist_head instances;
|
||||
pthread_rwlock_t rwlock;
|
||||
|
||||
struct ctrl_handle *ctrl;
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DMAIN,
|
||||
};
|
||||
|
||||
enum codec_type;
|
||||
|
||||
extern struct rtpsim_global *g_rtpsim;
|
||||
|
||||
struct rtpsim_connection *rtpsim_conn_find(struct rtpsim_instance *ri, const char *cname);
|
||||
struct rtpsim_connection *rtpsim_conn_reserve(struct rtpsim_instance *ri, const char *cname, enum codec_type codec);
|
||||
int rtpsim_conn_start(struct rtpsim_connection *rtpc);
|
||||
void rtpsim_conn_stop(struct rtpsim_connection *rtpc);
|
||||
void rtpsim_conn_unreserve(struct rtpsim_connection *rtpc);
|
||||
int rtpsim_conn_connect(struct rtpsim_connection *rtpc);
|
||||
|
||||
int rtpsource_ctrl_cmds_install(void);
|
560
contrib/rtp-load-gen/rtp-load-gen.c
Normal file
560
contrib/rtp-load-gen/rtp-load-gen.c
Normal file
@@ -0,0 +1,560 @@
|
||||
#include <liburing.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/stats.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "rtp_provider.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* use a separate rx-completion thread: submit from main, reap from completion */
|
||||
//#define USE_CQ_THREAD
|
||||
|
||||
/* use registered files: Doesn't seem to work with sockets? */
|
||||
//#define USE_REGISTERED_FILES
|
||||
|
||||
/* use registered buffers (mapped once into kernel, rather than at every write */
|
||||
#define USE_REGISTERED_BUFFERS
|
||||
|
||||
/* number of sockets/flows to create */
|
||||
#define NUM_FLOWS 4096
|
||||
|
||||
/* number of workers to spawn. Each worker will get an equal share of NR_FLOWS to work on */
|
||||
#define NR_WORKERS 4
|
||||
|
||||
/* size of rx/tx buffer for one RTP frame */
|
||||
#define BUF_SIZE 256
|
||||
|
||||
#define NUM_FLOWS_PER_WORKER (NUM_FLOWS/NR_WORKERS)
|
||||
|
||||
#define TX_BUF_IDX 0
|
||||
#define RX_BUF_IDX 1
|
||||
|
||||
struct rtpsim_global *g_rtpsim;
|
||||
|
||||
enum rtpsim_conn_ctr {
|
||||
RTP_CONN_CTR_TX_PKTS,
|
||||
RTP_CONN_CTR_TX_BYTES,
|
||||
RTP_CONN_CTR_RX_PKTS,
|
||||
RTP_CONN_CTR_RX_BYTES,
|
||||
RTP_CONN_CTR_RX_INVALID,
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc rtpsim_conn_ctrs[] = {
|
||||
[RTP_CONN_CTR_TX_PKTS] = { "tx_pkts:total", "Transmitted packets" },
|
||||
[RTP_CONN_CTR_TX_BYTES] = { "tx_bytes:total", "Transmitted bytes" },
|
||||
[RTP_CONN_CTR_RX_PKTS] = { "rx_pkts:total", "Received packets (total)" },
|
||||
[RTP_CONN_CTR_RX_BYTES] = { "rx_bytes:total", "Transmitted bytes" },
|
||||
[RTP_CONN_CTR_RX_INVALID] = { "rx_pkts:invalid", "Received packets (invalidl)" },
|
||||
};
|
||||
static const struct rate_ctr_group_desc rtpsim_conn_ctrg_desc = {
|
||||
.group_name_prefix = "rtpsim_conn",
|
||||
.group_description = "RTP Simulator Connection",
|
||||
.class_id = 0,
|
||||
.num_ctr = ARRAY_SIZE(rtpsim_conn_ctrs),
|
||||
.ctr_desc = rtpsim_conn_ctrs,
|
||||
};
|
||||
|
||||
enum rtpsim_ctr {
|
||||
RTP_INST_TIMERS_TOTAL,
|
||||
RTP_INST_TIMERS_LATE,
|
||||
};
|
||||
static const struct rate_ctr_desc rtpsim_ctrs[] = {
|
||||
[RTP_INST_TIMERS_TOTAL] = { "timers:total", "Timers expiring (total)" },
|
||||
[RTP_INST_TIMERS_LATE] = { "timers:late", "Timers expiring (late)" },
|
||||
};
|
||||
static const struct rate_ctr_group_desc rtpsim_ctrg_desc = {
|
||||
.group_name_prefix = "rtpsim",
|
||||
.group_description = "RTP Simulator Instance",
|
||||
.class_id = 0,
|
||||
.num_ctr = ARRAY_SIZE(rtpsim_ctrs),
|
||||
.ctr_desc = rtpsim_ctrs,
|
||||
};
|
||||
|
||||
struct rtpsim_instance *rtpsim_instance_init(void *ctx, const struct rtpsim_instance_cfg *rmp)
|
||||
{
|
||||
struct rtpsim_instance *ri = talloc_zero(ctx, struct rtpsim_instance);
|
||||
int rc;
|
||||
|
||||
if (!ri)
|
||||
return NULL;
|
||||
ri->connections_size = NUM_FLOWS_PER_WORKER;
|
||||
ri->connections = talloc_zero_size(ri, sizeof(struct rtpsim_connection *)*ri->connections_size);
|
||||
if (!ri->connections) {
|
||||
talloc_free(ri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ri->cfg = *rmp;
|
||||
rc = io_uring_queue_init(NUM_FLOWS_PER_WORKER*2, &ri->ring, 0);
|
||||
if (rc < 0) {
|
||||
talloc_free(ri);
|
||||
return NULL;
|
||||
}
|
||||
ri->ctrg = rate_ctr_group_alloc(ri, &rtpsim_ctrg_desc, rmp->num);
|
||||
OSMO_ASSERT(ri->ctrg);
|
||||
return ri;
|
||||
}
|
||||
|
||||
static int rtpsim_instance_conn_add(struct rtpsim_instance *ri, struct rtpsim_connection *rtpc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ri->connections_size; i++) {
|
||||
if (ri->connections[i] == NULL) {
|
||||
ri->connections[i] = rtpc;
|
||||
rtpc->idx = i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static struct rtpsim_connection *
|
||||
rtpsim_conn_open_bind(struct rtpsim_instance *ri, const struct rtpsim_connection_cfg *rcfg)
|
||||
{
|
||||
struct rtpsim_connection *rtpc = talloc_zero(ri, struct rtpsim_connection);
|
||||
struct osmo_sockaddr sa_local;
|
||||
int rc;
|
||||
|
||||
if (!rtpc)
|
||||
return NULL;
|
||||
|
||||
rtpc->inst = ri;
|
||||
rtpc->cfg = *rcfg;
|
||||
|
||||
osmo_sockaddr_str_to_sockaddr(&rtpc->cfg.local, &sa_local.u.sas);
|
||||
|
||||
rc = osmo_sock_init_osa(SOCK_DGRAM, IPPROTO_UDP, &sa_local, NULL, OSMO_SOCK_F_BIND);
|
||||
if (rc < 0) {
|
||||
talloc_free(rtpc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rtpc->fd = rc;
|
||||
rtpc->ctrg = rate_ctr_group_alloc(rtpc, &rtpsim_conn_ctrg_desc, rtpc->cfg.local.port);
|
||||
OSMO_ASSERT(rtpc->ctrg);
|
||||
#ifndef USE_REGISTERED_BUFFERS
|
||||
rtpc->tx.buf = talloc_zero_size(rtpc, BUF_SIZE);
|
||||
rtpc->rx.buf = talloc_zero_size(rtpc, BUF_SIZE);
|
||||
#endif
|
||||
OSMO_ASSERT(rtpsim_instance_conn_add(ri, rtpc) >= 0);
|
||||
|
||||
return rtpc;
|
||||
}
|
||||
|
||||
/* find a connection for given cname (may be NULL to find unused connection) */
|
||||
struct rtpsim_connection *rtpsim_conn_find(struct rtpsim_instance *ri, const char *cname)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ri->connections_size; i++) {
|
||||
struct rtpsim_connection *rtpc = ri->connections[i];
|
||||
if (!rtpc)
|
||||
continue;
|
||||
if (!rtpc->cname) {
|
||||
if (!cname)
|
||||
return rtpc;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(rtpc->cname, cname))
|
||||
return rtpc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* reserve a connection; associates cname with it */
|
||||
struct rtpsim_connection *rtpsim_conn_reserve(struct rtpsim_instance *ri, const char *cname,
|
||||
enum codec_type codec)
|
||||
{
|
||||
struct rtpsim_connection *rtpc;
|
||||
const struct rtp_provider *rtp_prov;
|
||||
|
||||
rtp_prov = rtp_provider_find("static"); // TODO: configurable */
|
||||
OSMO_ASSERT(rtp_prov);
|
||||
|
||||
rtpc = rtpsim_conn_find(ri, NULL);
|
||||
if (!rtpc)
|
||||
return NULL;
|
||||
|
||||
/* this is called from main thread, we cannot use per-thread talloc contexts
|
||||
* such as ri or rtpc */
|
||||
rtpc->cname = talloc_strdup(g_rtpsim, cname);
|
||||
rtpc->tx.rtp_prov_inst = rtp_provider_instance_alloc(g_rtpsim, rtp_prov, codec);
|
||||
OSMO_ASSERT(rtpc->tx.rtp_prov_inst);
|
||||
|
||||
/* re-start from zero transmit sequence number */
|
||||
rtpc->tx.seq = 0;
|
||||
|
||||
return rtpc;
|
||||
}
|
||||
|
||||
int rtpsim_conn_start(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
rtpc->tx.enabled = true;
|
||||
rtpc->rx.enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtpsim_conn_stop(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
/* disable Rx and Tx */
|
||||
rtpc->tx.enabled = false;
|
||||
rtpc->rx.enabled = false;
|
||||
}
|
||||
|
||||
/* unreserve a connection; stops all rx/tx and removes cname */
|
||||
void rtpsim_conn_unreserve(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
rtp_provider_instance_free(rtpc->tx.rtp_prov_inst);
|
||||
rtpc->tx.rtp_prov_inst = NULL;
|
||||
|
||||
talloc_free(rtpc->cname);
|
||||
rtpc->cname = NULL;
|
||||
}
|
||||
|
||||
/* connect a RTP connection to its remote peer (as in rtpc->cfg.remote) */
|
||||
int rtpsim_conn_connect(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
struct osmo_sockaddr sa_remote;
|
||||
int rc;
|
||||
|
||||
osmo_sockaddr_str_to_sockaddr(&rtpc->cfg.remote, &sa_remote.u.sas);
|
||||
rc = connect(rtpc->fd, &sa_remote.u.sa, sizeof(struct osmo_sockaddr));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* transmit one RTP frame for given connection */
|
||||
static int rtpsim_conn_tx_frame(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
struct rtp_hdr *rtph = (struct rtp_hdr *) rtpc->tx.buf;
|
||||
struct io_uring_sqe *sqe;
|
||||
uint8_t *payload;
|
||||
int rc;
|
||||
|
||||
rtph->version = RTP_VERSION;
|
||||
rtph->padding = 0;
|
||||
rtph->extension = 0;
|
||||
rtph->csrc_count = 0;
|
||||
rtph->marker = 0;
|
||||
rtph->payload_type = rtpc->cfg.pt;
|
||||
rtph->sequence = htons(rtpc->tx.seq++);
|
||||
rtph->timestamp = htonl(rtpc->tx.timestamp);
|
||||
rtpc->tx.timestamp += rtpc->cfg.duration;
|
||||
rtph->ssrc = htonl(rtpc->cfg.ssrc);
|
||||
payload = rtpc->tx.buf + sizeof(*rtph);
|
||||
/* add payload data */
|
||||
|
||||
rc = rtp_provider_instance_gen_frame(rtpc->tx.rtp_prov_inst, payload, BUF_SIZE-sizeof(*rtph));
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
rtpc->tx.buf_len = sizeof(*rtph) + rc;
|
||||
|
||||
sqe = io_uring_get_sqe(&rtpc->inst->ring);
|
||||
OSMO_ASSERT(sqe);
|
||||
sqe->user_data = rtpc->idx;
|
||||
#ifdef USE_REGISTERED_FILES
|
||||
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
||||
#ifdef USE_REGISTERED_BUFFERS
|
||||
io_uring_prep_write_fixed(sqe, rtpc->idx, rtpc->tx.buf, rtpc->tx.buf_len, 0, TX_BUF_IDX);
|
||||
#else
|
||||
io_uring_prep_write(sqe, rtpc->idx, rtpc->tx.buf, rtpc->tx.buf_len, 0);
|
||||
#endif
|
||||
#else /* REGISTERED FILES */
|
||||
#ifdef USE_REGISTERED_BUFFERS
|
||||
io_uring_prep_write_fixed(sqe, rtpc->fd, rtpc->tx.buf, rtpc->tx.buf_len, 0, TX_BUF_IDX);
|
||||
#else
|
||||
io_uring_prep_write(sqe, rtpc->fd, rtpc->tx.buf, rtpc->tx.buf_len, 0);
|
||||
#endif
|
||||
#endif /* REGISTERED_FILES */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* submit RX buffer for a RTP frame on given connection */
|
||||
static int rtpsim_conn_rx_prep(struct rtpsim_connection *rtpc)
|
||||
{
|
||||
struct io_uring_sqe *sqe;
|
||||
|
||||
sqe = io_uring_get_sqe(&rtpc->inst->ring);
|
||||
OSMO_ASSERT(sqe);
|
||||
sqe->user_data = 0x8000000 | rtpc->idx;
|
||||
#ifdef USE_REGISTERED_FILES
|
||||
io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
|
||||
/* FIXME */
|
||||
#else /* REGISTERED FILES */
|
||||
#ifdef USE_REGISTERED_BUFFERS
|
||||
io_uring_prep_read_fixed(sqe, rtpc->fd, rtpc->rx.buf, BUF_SIZE, 0, RX_BUF_IDX);
|
||||
#else
|
||||
io_uring_prep_read(sqe, rtpc->fd, rtpc->rx.buf, BUF_SIZE, 0);
|
||||
#endif
|
||||
#endif /* REGISTERED_FILES */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* process one completion entry */
|
||||
static void handle_completion(struct rtpsim_instance *ri, struct io_uring_cqe *cqe)
|
||||
{
|
||||
struct rtpsim_connection *rtpc = ri->connections[cqe->user_data & 0x7fffffff];
|
||||
OSMO_ASSERT(rtpc);
|
||||
|
||||
if (cqe->user_data & 0x80000000) {
|
||||
/* read */
|
||||
rate_ctr_inc(&rtpc->ctrg->ctr[RTP_CONN_CTR_RX_PKTS]);
|
||||
rate_ctr_add(&rtpc->ctrg->ctr[RTP_CONN_CTR_RX_BYTES], cqe->res);
|
||||
OSMO_ASSERT(cqe->res >= 0);
|
||||
} else {
|
||||
/* write */
|
||||
rate_ctr_inc(&rtpc->ctrg->ctr[RTP_CONN_CTR_TX_PKTS]);
|
||||
rate_ctr_add(&rtpc->ctrg->ctr[RTP_CONN_CTR_TX_BYTES], cqe->res);
|
||||
OSMO_ASSERT(cqe->res == sizeof(struct rtp_hdr) + 33);
|
||||
}
|
||||
io_uring_cqe_seen(&ri->ring, cqe);
|
||||
}
|
||||
|
||||
#ifdef USE_CQ_THREAD
|
||||
/* 'main' function for separate completion queue reaping thread */
|
||||
static void *reap_completion(void *_ri)
|
||||
{
|
||||
struct rtpsim_instance *ri = _ri;
|
||||
while (1) {
|
||||
struct io_uring_cqe *cqe;
|
||||
int rc;
|
||||
|
||||
rc = io_uring_wait_cqe(&ri->ring, &cqe);
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
handle_completion(ri, cqe);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int osmo_ctx_init(const char *id);
|
||||
|
||||
static void rtpsim_main(const struct rtpsim_instance_cfg *rmp)
|
||||
{
|
||||
struct rtpsim_instance *ri;
|
||||
struct rtpsim_connection *rtpc;
|
||||
int i, rc;
|
||||
|
||||
char namebuf[32];
|
||||
snprintf(namebuf, sizeof(namebuf), "rtpsim_worker%d", rmp->num);
|
||||
osmo_ctx_init(namebuf);
|
||||
|
||||
ri = rtpsim_instance_init(OTC_GLOBAL, rmp);
|
||||
OSMO_ASSERT(ri);
|
||||
|
||||
pthread_rwlock_wrlock(&g_rtpsim->rwlock);
|
||||
llist_add_tail(&ri->list, &g_rtpsim->instances);
|
||||
pthread_rwlock_unlock(&g_rtpsim->rwlock);
|
||||
|
||||
/* create desired number of sockets */
|
||||
printf("binding sockets\n");
|
||||
for (i = 0; i < rmp->num_flows; i++) {
|
||||
struct rtpsim_connection *rtpc;
|
||||
struct rtpsim_connection_cfg rcfg = {};
|
||||
rcfg.local = (struct osmo_sockaddr_str) {
|
||||
.af = AF_INET,
|
||||
.ip = "127.0.0.1",
|
||||
.port = rmp->base_port + 2*i,
|
||||
};
|
||||
rcfg.remote = (struct osmo_sockaddr_str) {
|
||||
.af = AF_INET,
|
||||
.ip = "127.0.0.1",
|
||||
.port = rmp->base_port + 2*i,
|
||||
};
|
||||
rcfg.pt = 3;
|
||||
rcfg.ssrc = 0x80000000 + rmp->base_port + i;
|
||||
rcfg.duration = 160; /* 8000 Hz sampling rate / 50 Hz RTP rate */
|
||||
|
||||
rtpc = rtpsim_conn_open_bind(ri, &rcfg);
|
||||
OSMO_ASSERT(rtpc);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* HACK */
|
||||
printf("connecting sockets\n");
|
||||
for (i = 0; i < rmp->num_flows; i++) {
|
||||
char namebuf[32];
|
||||
snprintf(namebuf, sizeof(namebuf), "conn%d", i);
|
||||
struct rtpsim_connection *rtpc = rtpsim_conn_reserve(ri, namebuf, CODEC_GSM_FR);
|
||||
OSMO_ASSERT(rtpc);
|
||||
OSMO_ASSERT(rtpsim_conn_connect(rtpc) == 0);
|
||||
OSMO_ASSERT(rtpsim_conn_start(rtpc) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_REGISTERED_FILES
|
||||
/* register all our file descriptors; seems to fail on 5.8.x ? */
|
||||
int fds[NUM_FLOWS_PER_WORKER];
|
||||
for (i = 0; i < ri->connections_size; i++) {
|
||||
if (!rtpc) {
|
||||
fds[i] = -1;
|
||||
continue;
|
||||
}
|
||||
rtpc = ri->connections[i];
|
||||
fds[i] = rtpc->fd;
|
||||
}
|
||||
printf("Registering %d files\n", i);
|
||||
rc = io_uring_register_files(&ri->ring, fds, i);
|
||||
printf("rc = %d: %s\n", rc, strerror(-rc));
|
||||
OSMO_ASSERT(rc == 0);
|
||||
#endif
|
||||
|
||||
#ifdef USE_REGISTERED_BUFFERS
|
||||
/* register two large buffers for Rx and Tx; assign per-connection
|
||||
* buffers within those two registered buffers */
|
||||
void *largebuf_tx = talloc_zero_size(ri, rmp->num_flows * BUF_SIZE);
|
||||
void *largebuf_rx = talloc_zero_size(ri, rmp->num_flows * BUF_SIZE);
|
||||
struct iovec iov[2] = {
|
||||
[TX_BUF_IDX] = {
|
||||
.iov_base = largebuf_tx,
|
||||
.iov_len = rmp->num_flows * BUF_SIZE,
|
||||
},
|
||||
[RX_BUF_IDX] = {
|
||||
.iov_base = largebuf_rx,
|
||||
.iov_len = rmp->num_flows * BUF_SIZE,
|
||||
},
|
||||
};
|
||||
printf("Registering buffers for %d sockets\n", i);
|
||||
rc = io_uring_register_buffers(&ri->ring, iov, ARRAY_SIZE(iov));
|
||||
printf("rc = %d: %s\n", rc, strerror(-rc));
|
||||
OSMO_ASSERT(rc == 0);
|
||||
for (i = 0; i < ri->connections_size; i++) {
|
||||
rtpc = ri->connections[i];
|
||||
if (!rtpc)
|
||||
continue;
|
||||
rtpc->tx.buf = largebuf_tx + (i * BUF_SIZE);
|
||||
rtpc->rx.buf = largebuf_rx + (i * BUF_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_CQ_THREAD
|
||||
/* start a separate completion thread instead of handling completions in-line */
|
||||
pthread_t complete;
|
||||
rc = pthread_create(&complete, NULL, reap_completion, ri);
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
#endif
|
||||
|
||||
/* start timerfd every 20ms */
|
||||
ri->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
OSMO_ASSERT(ri->timerfd >= 0);
|
||||
struct itimerspec its = (struct itimerspec) {
|
||||
.it_interval = { 0, 20*1000*1000 },
|
||||
.it_value = { 0, 20*1000*1000 },
|
||||
};
|
||||
rc = timerfd_settime(ri->timerfd, 0, &its, NULL);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
/* start transmitting */
|
||||
|
||||
while (1) {
|
||||
/* the assumption here is that every flow wants to write 50
|
||||
* packets per second, so we try try to submit one write for each
|
||||
* flow every 20ms */
|
||||
unsigned int submit_granularity = rmp->num_flows/50;
|
||||
/* number of 20ms timer expirations */
|
||||
uint64_t num_exp;
|
||||
unsigned int t;
|
||||
|
||||
if (submit_granularity <= 0)
|
||||
submit_granularity = 1;
|
||||
|
||||
/* read from timerfd to pace the 20ms inter packet interval */
|
||||
rc = read(ri->timerfd, &num_exp, sizeof(num_exp));
|
||||
OSMO_ASSERT(rc == sizeof(num_exp));
|
||||
|
||||
rate_ctr_add(&ri->ctrg->ctr[RTP_INST_TIMERS_TOTAL], num_exp);
|
||||
if (num_exp != 1) {
|
||||
fputc('X', stdout);
|
||||
rate_ctr_add(&ri->ctrg->ctr[RTP_INST_TIMERS_LATE], num_exp-1);
|
||||
} else {
|
||||
fputc('.', stdout);
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
for (t = 0; t < num_exp; t++) {
|
||||
for (i = 0; i < ri->connections_size; i++) {
|
||||
rtpc = ri->connections[i];
|
||||
if (!rtpc)
|
||||
continue;
|
||||
if (rtpc->tx.enabled)
|
||||
rtpsim_conn_tx_frame(rtpc);
|
||||
if (rtpc->rx.enabled)
|
||||
rtpsim_conn_rx_prep(rtpc);
|
||||
if ((i % submit_granularity) == 0) {
|
||||
int pending = io_uring_submit(&ri->ring);
|
||||
|
||||
#ifndef USE_CQ_THREAD
|
||||
for (int j = 0; j < pending; j++) {
|
||||
struct io_uring_cqe *cqe;
|
||||
int rc;
|
||||
|
||||
rc = io_uring_wait_cqe(&ri->ring, &cqe);
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
handle_completion(ri, cqe);
|
||||
}
|
||||
#endif /* USE_CQ_THREAD */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void *rtpsim_worker_thread(void *_rmp)
|
||||
{
|
||||
rtpsim_main((struct rtpsim_instance_cfg *)_rmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pthread_t worker[NR_WORKERS];
|
||||
struct rtpsim_instance_cfg rmp[NR_WORKERS];
|
||||
int i, rc;
|
||||
|
||||
g_rtpsim = talloc_zero(NULL, struct rtpsim_global);
|
||||
OSMO_ASSERT(g_rtpsim);
|
||||
INIT_LLIST_HEAD(&g_rtpsim->instances);
|
||||
pthread_rwlock_init(&g_rtpsim->rwlock, NULL);
|
||||
|
||||
osmo_init_logging2(g_rtpsim, NULL);
|
||||
// osmo_stats_init(g_rtpsim);
|
||||
|
||||
/* Create worker threads */
|
||||
for (i = 0; i < NR_WORKERS; i++) {
|
||||
int rc;
|
||||
rmp[i].num = i;
|
||||
rmp[i].num_flows = NUM_FLOWS_PER_WORKER;
|
||||
rmp[i].base_port = 10000 + i * (2 * rmp[i].num_flows);
|
||||
rc = pthread_create(&worker[i], NULL, rtpsim_worker_thread, &rmp[i]);
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
}
|
||||
|
||||
/* CTRL interface */
|
||||
//g_rtpsim->ctrl = ctrl_interface_setup_dynip(g_rss, ctrl_vty_get_bind_addr(), 11111, NULL);
|
||||
g_rtpsim->ctrl = ctrl_interface_setup_dynip(g_rtpsim, "127.0.0.1", 11111, NULL);
|
||||
OSMO_ASSERT(g_rtpsim->ctrl);
|
||||
rc = rtpsource_ctrl_cmds_install();
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
while (1) {
|
||||
osmo_select_main(0);
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_WORKERS; i++) {
|
||||
pthread_join(worker[i], NULL);
|
||||
}
|
||||
}
|
71
contrib/rtp-load-gen/rtp_provider.c
Normal file
71
contrib/rtp-load-gen/rtp_provider.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include "rtp_provider.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static LLIST_HEAD(g_providers);
|
||||
|
||||
const struct value_string codec_type_names[] = {
|
||||
{ CODEC_ULAW, "ULAW" },
|
||||
{ CODEC_ALAW, "ALAW" },
|
||||
{ CODEC_GSM_FR, "GSM_FR" },
|
||||
{ CODEC_GSM_EFR, "GSM_EFR" },
|
||||
{ CODEC_GSM_HR, "GSM_HR" },
|
||||
{ CODEC_AMR_4_75, "AMR_4_75" },
|
||||
{ CODEC_AMR_5_15, "AMR_5_15" },
|
||||
{ CODEC_AMR_5_90, "AMR_5_90" },
|
||||
{ CODEC_AMR_6_70, "AMR_6_70" },
|
||||
{ CODEC_AMR_7_40, "AMR_7_40" },
|
||||
{ CODEC_AMR_7_95, "AMR_7_95" },
|
||||
{ CODEC_AMR_10_2, "AMR_10_2" },
|
||||
{ CODEC_AMR_12_2, "AMR_12_2" },
|
||||
{ CODEC_AMR_SID, "AMR_SID" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
void rtp_provider_register(struct rtp_provider *prov)
|
||||
{
|
||||
llist_add_tail(&prov->list, &g_providers);
|
||||
}
|
||||
|
||||
const struct rtp_provider *rtp_provider_find(const char *name)
|
||||
{
|
||||
struct rtp_provider *p;
|
||||
llist_for_each_entry(p, &g_providers, list) {
|
||||
if (!strcmp(name, p->name))
|
||||
return p;
|
||||
}
|
||||
LOGP(DMAIN, LOGL_ERROR, "Couldn't find RTP provider '%s'\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rtp_provider_instance *
|
||||
rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec)
|
||||
{
|
||||
struct rtp_provider_instance *pi;
|
||||
|
||||
pi = talloc_zero(ctx, struct rtp_provider_instance);
|
||||
if (!pi)
|
||||
return NULL;
|
||||
|
||||
pi->provider = provider;
|
||||
pi->codec = codec;
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
void rtp_provider_instance_free(struct rtp_provider_instance *pi)
|
||||
{
|
||||
llist_del(&pi->list);
|
||||
talloc_free(pi);
|
||||
}
|
||||
|
||||
int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
|
||||
{
|
||||
OSMO_ASSERT(pi->provider);
|
||||
return pi->provider->rtp_gen(pi, out, out_size);
|
||||
}
|
57
contrib/rtp-load-gen/rtp_provider.h
Normal file
57
contrib/rtp-load-gen/rtp_provider.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
enum codec_type {
|
||||
CODEC_ULAW,
|
||||
CODEC_ALAW,
|
||||
CODEC_GSM_FR,
|
||||
CODEC_GSM_EFR,
|
||||
CODEC_GSM_HR,
|
||||
CODEC_AMR_4_75,
|
||||
CODEC_AMR_5_15,
|
||||
CODEC_AMR_5_90,
|
||||
CODEC_AMR_6_70,
|
||||
CODEC_AMR_7_40,
|
||||
CODEC_AMR_7_95,
|
||||
CODEC_AMR_10_2,
|
||||
CODEC_AMR_12_2,
|
||||
CODEC_AMR_SID,
|
||||
_NUM_CODECS
|
||||
};
|
||||
|
||||
extern const struct value_string codec_type_names[];
|
||||
|
||||
struct rtp_provider_instance;
|
||||
|
||||
struct rtp_provider {
|
||||
/* global list of RTP providers */
|
||||
struct llist_head list;
|
||||
const char *name;
|
||||
|
||||
/* create/initialie a RTP provider with specified argument string */
|
||||
int (*setup)(struct rtp_provider_instance *inst, const char *arg);
|
||||
|
||||
/* generate the next RTP packet; return length in octests or negative on error */
|
||||
int (*rtp_gen)(struct rtp_provider_instance *inst, uint8_t *out, size_t out_size);
|
||||
};
|
||||
|
||||
struct rtp_provider_instance {
|
||||
/* entry in global list of RTP provider instances */
|
||||
struct llist_head list;
|
||||
/* pointer to provider of which we are an instance */
|
||||
const struct rtp_provider *provider;
|
||||
/* codec payload we are to generate */
|
||||
enum codec_type codec;
|
||||
|
||||
/* private user data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
void rtp_provider_register(struct rtp_provider *prov);
|
||||
const struct rtp_provider *rtp_provider_find(const char *name);
|
||||
|
||||
struct rtp_provider_instance *rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec);
|
||||
void rtp_provider_instance_free(struct rtp_provider_instance *pi);
|
||||
int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size);
|
108
contrib/rtp-load-gen/rtp_provider_static.c
Normal file
108
contrib/rtp-load-gen/rtp_provider_static.c
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include "rtp_provider.h"
|
||||
#include "internal.h"
|
||||
|
||||
static struct rtp_provider static_provider;
|
||||
|
||||
static const uint8_t len4codec[_NUM_CODECS] = {
|
||||
[CODEC_ULAW] = 160,
|
||||
[CODEC_ALAW] = 160,
|
||||
[CODEC_GSM_FR] = GSM_FR_BYTES,
|
||||
[CODEC_GSM_EFR] = GSM_EFR_BYTES,
|
||||
[CODEC_GSM_HR] = GSM_HR_BYTES,
|
||||
[CODEC_AMR_4_75] = 12,
|
||||
[CODEC_AMR_5_15] = 13,
|
||||
[CODEC_AMR_5_90] = 15,
|
||||
[CODEC_AMR_6_70] = 17,
|
||||
[CODEC_AMR_7_40] = 19,
|
||||
[CODEC_AMR_7_95] = 20,
|
||||
[CODEC_AMR_10_2] = 26,
|
||||
[CODEC_AMR_12_2] = 31,
|
||||
[CODEC_AMR_SID] = 5,
|
||||
};
|
||||
|
||||
/* generate a static / fixed RTP payload of matching codec/mode */
|
||||
static int rtp_gen_static(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
OSMO_ASSERT(pi->provider == &static_provider);
|
||||
|
||||
len = len4codec[pi->codec];
|
||||
if (out_size < len) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "out_size %zu < %u\n", out_size, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(out, 0, len);
|
||||
|
||||
switch (pi->codec) {
|
||||
case CODEC_ULAW:
|
||||
case CODEC_ALAW:
|
||||
break;
|
||||
case CODEC_GSM_FR:
|
||||
out[0] = (out[0] & 0x0f) | 0xD0; /* mask in first four bit for FR */
|
||||
break;
|
||||
case CODEC_GSM_EFR:
|
||||
out[0] = (out[0] & 0x0f) | 0xC0; /* mask in first four bit for EFR */
|
||||
break;
|
||||
case CODEC_GSM_HR:
|
||||
break;
|
||||
case CODEC_AMR_4_75:
|
||||
out[0] = 0 << 4;
|
||||
out[1] = 0 << 3;
|
||||
break;
|
||||
case CODEC_AMR_5_15:
|
||||
out[0] = 1 << 4;
|
||||
out[1] = 1 << 3;
|
||||
break;
|
||||
case CODEC_AMR_5_90:
|
||||
out[0] = 2 << 4;
|
||||
out[1] = 2 << 3;
|
||||
break;
|
||||
case CODEC_AMR_6_70:
|
||||
out[0] = 3 << 4;
|
||||
out[1] = 3 << 3;
|
||||
break;
|
||||
case CODEC_AMR_7_40:
|
||||
out[0] = 4 << 4;
|
||||
out[1] = 4 << 3;
|
||||
break;
|
||||
case CODEC_AMR_7_95:
|
||||
out[0] = 5 << 4;
|
||||
out[1] = 5 << 3;
|
||||
break;
|
||||
case CODEC_AMR_10_2:
|
||||
out[0] = 6 << 4;
|
||||
out[1] = 6 << 3;
|
||||
break;
|
||||
case CODEC_AMR_12_2:
|
||||
out[0] = 7 << 4;
|
||||
out[1] = 7 << 3;
|
||||
break;
|
||||
case CODEC_AMR_SID:
|
||||
out[0] = 2 << 4; /* CMR: 5.90 */
|
||||
out[0] = 8 << 3;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static struct rtp_provider static_provider = {
|
||||
.name = "static",
|
||||
.rtp_gen = &rtp_gen_static,
|
||||
};
|
||||
|
||||
static void __attribute__((constructor)) rtp_provider_static_constr(void)
|
||||
{
|
||||
rtp_provider_register(&static_provider);
|
||||
}
|
11
contrib/simcom2rtp/Makefile
Normal file
11
contrib/simcom2rtp/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
CFLAGS:= -O2 -g -Wall $(shell pkg-config --cflags libosmocore libosmotrau)
|
||||
LIBS:= $(shell pkg-config --libs libosmocore libosmotrau)
|
||||
|
||||
all: osmo-simcom2rtp
|
||||
|
||||
osmo-simcom2rtp: g711.o g711_table.o simcom2rtp.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^
|
||||
|
313
contrib/simcom2rtp/g711.c
Normal file
313
contrib/simcom2rtp/g711.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without
|
||||
* charge.
|
||||
*
|
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
|
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
||||
*
|
||||
* Sun source code is provided with no support and without any obligation on
|
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction,
|
||||
* modification or enhancement.
|
||||
*
|
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
|
||||
* OR ANY PART THEREOF.
|
||||
*
|
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
||||
* or profits or other special, indirect and consequential damages, even if
|
||||
* Sun has been advised of the possibility of such damages.
|
||||
*
|
||||
* Sun Microsystems, Inc.
|
||||
* 2550 Garcia Avenue
|
||||
* Mountain View, California 94043
|
||||
*/
|
||||
/*
|
||||
* December 30, 1994:
|
||||
* Functions linear2alaw, linear2ulaw have been updated to correctly
|
||||
* convert unquantized 16 bit values.
|
||||
* Tables for direct u- to A-law and A- to u-law conversions have been
|
||||
* corrected.
|
||||
* Borge Lindberg, Center for PersonKommunikation, Aalborg University.
|
||||
* bli@cpk.auc.dk
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Downloaded from comp.speech site in Cambridge.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "g711.h"
|
||||
|
||||
/*
|
||||
* g711.c
|
||||
*
|
||||
* u-law, A-law and linear PCM conversions.
|
||||
* Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.c
|
||||
*/
|
||||
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
|
||||
#define QUANT_MASK (0xf) /* Quantization field mask. */
|
||||
#define NSEGS (8) /* Number of A-law segments. */
|
||||
#define SEG_SHIFT (4) /* Left shift for segment number. */
|
||||
#define SEG_MASK (0x70) /* Segment field mask. */
|
||||
|
||||
static short seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
|
||||
0x1FF, 0x3FF, 0x7FF, 0xFFF};
|
||||
static short seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
|
||||
0x3FF, 0x7FF, 0xFFF, 0x1FFF};
|
||||
|
||||
/* copy from CCITT G.711 specifications */
|
||||
unsigned char _u2a[128] = { /* u- to A-law conversions */
|
||||
1, 1, 2, 2, 3, 3, 4, 4,
|
||||
5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 27, 29, 31, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44,
|
||||
46, 48, 49, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 58, 59, 60, 61, 62,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
/* corrected:
|
||||
81, 82, 83, 84, 85, 86, 87, 88,
|
||||
should be: */
|
||||
80, 82, 83, 84, 85, 86, 87, 88,
|
||||
89, 90, 91, 92, 93, 94, 95, 96,
|
||||
97, 98, 99, 100, 101, 102, 103, 104,
|
||||
105, 106, 107, 108, 109, 110, 111, 112,
|
||||
113, 114, 115, 116, 117, 118, 119, 120,
|
||||
121, 122, 123, 124, 125, 126, 127, 128};
|
||||
|
||||
unsigned char _a2u[128] = { /* A- to u-law conversions */
|
||||
1, 3, 5, 7, 9, 11, 13, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 32, 33, 33, 34, 34, 35, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 48, 49, 49,
|
||||
50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 64,
|
||||
65, 66, 67, 68, 69, 70, 71, 72,
|
||||
/* corrected:
|
||||
73, 74, 75, 76, 77, 78, 79, 79,
|
||||
should be: */
|
||||
73, 74, 75, 76, 77, 78, 79, 80,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127};
|
||||
|
||||
static short search(
|
||||
short val,
|
||||
short *table,
|
||||
short size)
|
||||
{
|
||||
short i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (val <= *table++)
|
||||
return (i);
|
||||
}
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*
|
||||
* linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
|
||||
*
|
||||
* linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
|
||||
*
|
||||
* Linear Input Code Compressed Code
|
||||
* ------------------------ ---------------
|
||||
* 0000000wxyza 000wxyz
|
||||
* 0000001wxyza 001wxyz
|
||||
* 000001wxyzab 010wxyz
|
||||
* 00001wxyzabc 011wxyz
|
||||
* 0001wxyzabcd 100wxyz
|
||||
* 001wxyzabcde 101wxyz
|
||||
* 01wxyzabcdef 110wxyz
|
||||
* 1wxyzabcdefg 111wxyz
|
||||
*
|
||||
* For further information see John C. Bellamy's Digital Telephony, 1982,
|
||||
* John Wiley & Sons, pps 98-111 and 472-476.
|
||||
*/
|
||||
unsigned char
|
||||
linear2alaw(short pcm_val) /* 2's complement (16-bit range) */
|
||||
{
|
||||
short mask;
|
||||
short seg;
|
||||
unsigned char aval;
|
||||
|
||||
pcm_val = pcm_val >> 3;
|
||||
|
||||
if (pcm_val >= 0) {
|
||||
mask = 0xD5; /* sign (7th) bit = 1 */
|
||||
} else {
|
||||
mask = 0x55; /* sign bit = 0 */
|
||||
pcm_val = -pcm_val - 1;
|
||||
}
|
||||
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
seg = search(pcm_val, seg_aend, 8);
|
||||
|
||||
/* Combine the sign, segment, and quantization bits. */
|
||||
|
||||
if (seg >= 8) /* out of range, return maximum value. */
|
||||
return (unsigned char) (0x7F ^ mask);
|
||||
else {
|
||||
aval = (unsigned char) seg << SEG_SHIFT;
|
||||
if (seg < 2)
|
||||
aval |= (pcm_val >> 1) & QUANT_MASK;
|
||||
else
|
||||
aval |= (pcm_val >> seg) & QUANT_MASK;
|
||||
return (aval ^ mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* alaw2linear() - Convert an A-law value to 16-bit linear PCM
|
||||
*
|
||||
*/
|
||||
short
|
||||
alaw2linear(
|
||||
unsigned char a_val)
|
||||
{
|
||||
short t;
|
||||
short seg;
|
||||
|
||||
a_val ^= 0x55;
|
||||
|
||||
t = (a_val & QUANT_MASK) << 4;
|
||||
seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
|
||||
switch (seg) {
|
||||
case 0:
|
||||
t += 8;
|
||||
break;
|
||||
case 1:
|
||||
t += 0x108;
|
||||
break;
|
||||
default:
|
||||
t += 0x108;
|
||||
t <<= seg - 1;
|
||||
}
|
||||
return ((a_val & SIGN_BIT) ? t : -t);
|
||||
}
|
||||
|
||||
#define BIAS (0x84) /* Bias for linear code. */
|
||||
#define CLIP 8159
|
||||
|
||||
/*
|
||||
* linear2ulaw() - Convert a linear PCM value to u-law
|
||||
*
|
||||
* In order to simplify the encoding process, the original linear magnitude
|
||||
* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
|
||||
* (33 - 8191). The result can be seen in the following encoding table:
|
||||
*
|
||||
* Biased Linear Input Code Compressed Code
|
||||
* ------------------------ ---------------
|
||||
* 00000001wxyza 000wxyz
|
||||
* 0000001wxyzab 001wxyz
|
||||
* 000001wxyzabc 010wxyz
|
||||
* 00001wxyzabcd 011wxyz
|
||||
* 0001wxyzabcde 100wxyz
|
||||
* 001wxyzabcdef 101wxyz
|
||||
* 01wxyzabcdefg 110wxyz
|
||||
* 1wxyzabcdefgh 111wxyz
|
||||
*
|
||||
* Each biased linear code has a leading 1 which identifies the segment
|
||||
* number. The value of the segment number is equal to 7 minus the number
|
||||
* of leading 0's. The quantization interval is directly available as the
|
||||
* four bits wxyz. * The trailing bits (a - h) are ignored.
|
||||
*
|
||||
* Ordinarily the complement of the resulting code word is used for
|
||||
* transmission, and so the code word is complemented before it is returned.
|
||||
*
|
||||
* For further information see John C. Bellamy's Digital Telephony, 1982,
|
||||
* John Wiley & Sons, pps 98-111 and 472-476.
|
||||
*/
|
||||
unsigned char
|
||||
linear2ulaw(
|
||||
short pcm_val) /* 2's complement (16-bit range) */
|
||||
{
|
||||
short mask;
|
||||
short seg;
|
||||
unsigned char uval;
|
||||
|
||||
/* Get the sign and the magnitude of the value. */
|
||||
pcm_val = pcm_val >> 2;
|
||||
if (pcm_val < 0) {
|
||||
pcm_val = -pcm_val;
|
||||
mask = 0x7F;
|
||||
} else {
|
||||
mask = 0xFF;
|
||||
}
|
||||
if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */
|
||||
pcm_val += (BIAS >> 2);
|
||||
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
seg = search(pcm_val, seg_uend, 8);
|
||||
|
||||
/*
|
||||
* Combine the sign, segment, quantization bits;
|
||||
* and complement the code word.
|
||||
*/
|
||||
if (seg >= 8) /* out of range, return maximum value. */
|
||||
return (unsigned char) (0x7F ^ mask);
|
||||
else {
|
||||
uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
|
||||
return (uval ^ mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* ulaw2linear() - Convert a u-law value to 16-bit linear PCM
|
||||
*
|
||||
* First, a biased linear code is derived from the code word. An unbiased
|
||||
* output can then be obtained by subtracting 33 from the biased code.
|
||||
*
|
||||
* Note that this function expects to be passed the complement of the
|
||||
* original code word. This is in keeping with ISDN conventions.
|
||||
*/
|
||||
short
|
||||
ulaw2linear(
|
||||
unsigned char u_val)
|
||||
{
|
||||
short t;
|
||||
|
||||
/* Complement to obtain normal u-law value. */
|
||||
u_val = ~u_val;
|
||||
|
||||
/*
|
||||
* Extract and bias the quantization bits. Then
|
||||
* shift up by the segment number and subtract out the bias.
|
||||
*/
|
||||
t = ((u_val & QUANT_MASK) << 3) + BIAS;
|
||||
t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
|
||||
|
||||
return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
|
||||
}
|
||||
|
||||
/* A-law to u-law conversion */
|
||||
unsigned char
|
||||
alaw2ulaw(
|
||||
unsigned char aval)
|
||||
{
|
||||
aval &= 0xff;
|
||||
return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
|
||||
(0x7F ^ _a2u[aval ^ 0x55]));
|
||||
}
|
||||
|
||||
/* u-law to A-law conversion */
|
||||
unsigned char
|
||||
ulaw2alaw(
|
||||
unsigned char uval)
|
||||
{
|
||||
uval &= 0xff;
|
||||
return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
|
||||
(0x55 ^ (_u2a[0x7F ^ uval] - 1)));
|
||||
}
|
||||
|
||||
/* ---------- end of g711.c ----------------------------------------------------- */
|
27
contrib/simcom2rtp/g711.h
Normal file
27
contrib/simcom2rtp/g711.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* g711.h
|
||||
*
|
||||
* u-law, A-law and linear PCM conversions.
|
||||
* Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.h
|
||||
*/
|
||||
|
||||
#ifndef _G711_H_
|
||||
#define _G711_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
unsigned char linear2alaw(short pcm_val);
|
||||
short alaw2linear(unsigned char a_val);
|
||||
unsigned char linear2ulaw(short pcm_val);
|
||||
short ulaw2linear(unsigned char u_val);
|
||||
unsigned char alaw2ulaw(unsigned char aval);
|
||||
unsigned char ulaw2alaw(unsigned char uval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _G711_H_ */
|
102
contrib/simcom2rtp/g711_table.c
Normal file
102
contrib/simcom2rtp/g711_table.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef G711_TABLE_H
|
||||
#define G711_TABLE_H
|
||||
|
||||
#include "g711.h"
|
||||
|
||||
/* 16384 entries per table (16 bit) */
|
||||
unsigned char linear_to_alaw[65536];
|
||||
unsigned char linear_to_ulaw[65536];
|
||||
|
||||
/* 16384 entries per table (8 bit) */
|
||||
unsigned short alaw_to_linear[256];
|
||||
unsigned short ulaw_to_linear[256];
|
||||
|
||||
static void build_linear_to_xlaw_table(unsigned char *linear_to_xlaw,
|
||||
unsigned char (*linear2xlaw)(short))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<65536;i++){
|
||||
linear_to_xlaw[i] = linear2xlaw((short) i);
|
||||
}
|
||||
}
|
||||
|
||||
static void build_xlaw_to_linear_table(unsigned short *xlaw_to_linear,
|
||||
short (*xlaw2linear)(unsigned char))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<256;i++){
|
||||
xlaw_to_linear[i] = (unsigned short) xlaw2linear(i);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcm16_to_xlaw(unsigned char *linear_to_xlaw, int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
int i;
|
||||
const unsigned short *s_samples;
|
||||
|
||||
s_samples = (const unsigned short *)src_samples;
|
||||
|
||||
for (i=0; i < src_length / 2; i++)
|
||||
{
|
||||
dst_samples[i] = linear_to_xlaw[s_samples[i]];
|
||||
}
|
||||
}
|
||||
|
||||
static void xlaw_to_pcm16(unsigned short *xlaw_to_linear, int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s_samples;
|
||||
unsigned short *d_samples;
|
||||
|
||||
s_samples = (unsigned char *) src_samples;
|
||||
d_samples = (unsigned short *)dst_samples;
|
||||
|
||||
for (i=0; i < src_length; i++)
|
||||
{
|
||||
d_samples[i] = xlaw_to_linear[s_samples[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void pcm16_to_alaw(int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
pcm16_to_xlaw(linear_to_alaw, src_length, src_samples, dst_samples);
|
||||
}
|
||||
|
||||
void pcm16_to_ulaw(int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
pcm16_to_xlaw(linear_to_ulaw, src_length, src_samples, dst_samples);
|
||||
}
|
||||
|
||||
void alaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
xlaw_to_pcm16(alaw_to_linear, src_length, src_samples, dst_samples);
|
||||
}
|
||||
|
||||
void ulaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
|
||||
{
|
||||
xlaw_to_pcm16(ulaw_to_linear, src_length, src_samples, dst_samples);
|
||||
}
|
||||
|
||||
void pcm16_alaw_tableinit()
|
||||
{
|
||||
build_linear_to_xlaw_table(linear_to_alaw, linear2alaw);
|
||||
}
|
||||
|
||||
void pcm16_ulaw_tableinit()
|
||||
{
|
||||
build_linear_to_xlaw_table(linear_to_ulaw, linear2ulaw);
|
||||
}
|
||||
|
||||
void alaw_pcm16_tableinit()
|
||||
{
|
||||
build_xlaw_to_linear_table(alaw_to_linear, alaw2linear);
|
||||
}
|
||||
|
||||
void ulaw_pcm16_tableinit()
|
||||
{
|
||||
build_xlaw_to_linear_table(ulaw_to_linear, ulaw2linear);
|
||||
}
|
||||
|
||||
#endif // G711_TABLE_H
|
14
contrib/simcom2rtp/g711_table.h
Normal file
14
contrib/simcom2rtp/g711_table.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef G711_TABLE_H
|
||||
#define G711_TABLE_H
|
||||
|
||||
void pcm16_to_alaw(int length, const char *src_samples, char *dst_samples);
|
||||
void pcm16_to_ulaw(int length, const char *src_samples, char *dst_samples);
|
||||
void alaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
|
||||
void ulaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
|
||||
|
||||
void pcm16_alaw_tableinit();
|
||||
void pcm16_ulaw_tableinit();
|
||||
void alaw_pcm16_tableinit();
|
||||
void ulaw_pcm16_tableinit();
|
||||
|
||||
#endif // G711_TABLE_H
|
218
contrib/simcom2rtp/simcom2rtp.c
Normal file
218
contrib/simcom2rtp/simcom2rtp.c
Normal file
@@ -0,0 +1,218 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/serial.h>
|
||||
|
||||
#include <osmocom/trau/osmo_ortp.h>
|
||||
|
||||
#include "g711.h"
|
||||
|
||||
#define RTP_PT_PCMU 0
|
||||
#define RTP_PT_PCMA 8
|
||||
|
||||
struct modem_state {
|
||||
struct osmo_fd data_fd;
|
||||
struct osmo_rtp_socket *rtp;
|
||||
/* queue of linear PCM audio in RTP -> modem direction */
|
||||
struct llist_head rtp2modem;
|
||||
/* message buffer used if samples insufficient for next RTP frame were received */
|
||||
struct msgb *modem2rtp;
|
||||
};
|
||||
|
||||
static void *g_tall_ctx;
|
||||
|
||||
|
||||
/* call-back on received RTP data */
|
||||
static void ortp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *payload,
|
||||
unsigned int payload_len, uint16_t seq_nr, uint32_t timestamp, bool marker)
|
||||
{
|
||||
/* we received a RTP frame */
|
||||
struct modem_state *ms = rs->priv;
|
||||
struct msgb *msg = msgb_alloc(payload_len*2, "RTP Rx");
|
||||
unsigned int i;
|
||||
int16_t *out;
|
||||
|
||||
OSMO_ASSERT(msg);
|
||||
|
||||
out = (int16_t *) msgb_put(msg, payload_len*2);
|
||||
|
||||
if (payload_len != 160) {
|
||||
fprintf(stderr, "RTP payload length %d != 160, dropping\n", payload_len);
|
||||
msgb_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* convert from Alaw to linear PCM (160 -> 320 bytes) */
|
||||
for (i = 0; i < payload_len; i++)
|
||||
out[i] = alaw2linear(payload[i]);
|
||||
|
||||
/* append to the write queue */
|
||||
msgb_enqueue(&ms->rtp2modem, msg);
|
||||
ms->data_fd.when |= OSMO_FD_WRITE;
|
||||
}
|
||||
|
||||
static void modem2rtp(struct modem_state *ms, const uint8_t *data, unsigned int len)
|
||||
{
|
||||
const int16_t *data16 = (const int16_t *)data;
|
||||
unsigned int samples = len / 2;
|
||||
unsigned int offset = 0;
|
||||
unsigned int i;
|
||||
|
||||
/* samples are always 16bit, we cannot read half a sample */
|
||||
OSMO_ASSERT((len & 1) == 0);
|
||||
|
||||
/* first complete any pending incomplete RTP frame */
|
||||
if (ms->modem2rtp) {
|
||||
struct msgb *msg = ms->modem2rtp;
|
||||
unsigned int missing_samples = 160 - msgb_length(msg);
|
||||
for (i = 0; i < missing_samples; i++) {
|
||||
if (i >= samples)
|
||||
break;
|
||||
msgb_put_u8(msg, linear2alaw(data16[i]));
|
||||
}
|
||||
offset = i;
|
||||
if (msgb_length(msg) == 160) {
|
||||
osmo_rtp_send_frame_ext(ms->rtp, msgb_data(msg), msgb_length(msg), 160, false);
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* then send as many RTP frames as we have samples */
|
||||
for (offset = offset; offset + 160 <= samples; offset += 160) {
|
||||
uint8_t buf[160];
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
buf[i] = linear2alaw(data16[offset + i]);
|
||||
osmo_rtp_send_frame_ext(ms->rtp, buf, sizeof(buf), 160, false);
|
||||
}
|
||||
|
||||
/* store remainder in msgb */
|
||||
if (offset < samples) {
|
||||
struct msgb *msg = msgb_alloc_c(ms, 160, "modem2rtp");
|
||||
OSMO_ASSERT(msg);
|
||||
OSMO_ASSERT(len - offset < 160);
|
||||
for (i = 0; i < len - offset; i++)
|
||||
msgb_put_u8(msg, linear2alaw(data16[offset + i]));
|
||||
ms->modem2rtp = msg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* call back on file descriptor events of the modem DATA ttyUSB device */
|
||||
static int modem_data_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct modem_state *ms = ofd->data;
|
||||
int rc;
|
||||
|
||||
if (what & OSMO_FD_READ) {
|
||||
/* SIM5360 USB AUDIO Application Note v1.01 states 1600 bytes every 100ms */
|
||||
uint8_t rx_buf[1600];
|
||||
rc = read(ofd->fd, rx_buf, sizeof(rx_buf));
|
||||
OSMO_ASSERT(rc > 0);
|
||||
modem2rtp(ms, rx_buf, rc);
|
||||
}
|
||||
|
||||
if (what & OSMO_FD_WRITE) {
|
||||
struct msgb *msg = msgb_dequeue(&ms->rtp2modem);
|
||||
if (!msg)
|
||||
ofd->when &= ~OSMO_FD_WRITE;
|
||||
else {
|
||||
/* SIM5300 USB AUDIO Application Note v1.01 states 640 bytes every 40ms;
|
||||
* we simply write every RTP frame individually (320 bytes every 20ms) */
|
||||
rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
|
||||
if (rc != msgb_length(msg))
|
||||
fprintf(stderr, "Short write: %d < %u\n", rc, msgb_length(msg));
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int modem_data_open(struct modem_state *ms, const char *basepath)
|
||||
{
|
||||
char fname[PATH_MAX+1];
|
||||
int fd;
|
||||
|
||||
/* the assumption is that the caller provides something like
|
||||
* "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1" */
|
||||
snprintf(fname, sizeof(fname), "%s.0-port0", basepath);
|
||||
|
||||
fd = osmo_serial_init(fname, 921600);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "failed to open device '%s': %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
osmo_fd_setup(&ms->data_fd, fd, OSMO_FD_READ, modem_data_fd_cb, ms, 0);
|
||||
osmo_fd_register(&ms->data_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct modem_state *modem_create(void *ctx)
|
||||
{
|
||||
struct modem_state *ms = talloc_zero(ctx, struct modem_state);
|
||||
int rc;
|
||||
|
||||
INIT_LLIST_HEAD(&ms->rtp2modem);
|
||||
|
||||
ms->rtp = osmo_rtp_socket_create(ms, 0);
|
||||
OSMO_ASSERT(ms->rtp);
|
||||
osmo_rtp_socket_set_pt(ms->rtp, RTP_PT_PCMA);
|
||||
ms->rtp->priv = ms;
|
||||
ms->rtp->rx_cb = ortp_rx_cb;
|
||||
|
||||
rc = osmo_rtp_socket_bind(ms->rtp, "0.0.0.0", 1111);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
rc = osmo_rtp_socket_connect(ms->rtp, "127.0.0.1", 2222);
|
||||
//rc = osmo_rtp_socket_autoconnect(ms->rtp);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
osmo_rtp_set_source_desc(ms->rtp, "cname", "simcom2rtp", NULL, NULL, NULL,
|
||||
"osmo-simcom2rtp", NULL);
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
talloc_enable_null_tracking();
|
||||
g_tall_ctx = talloc_named_const(NULL, 1, "simcom2rtp");
|
||||
|
||||
msgb_talloc_ctx_init(g_tall_ctx, 0);
|
||||
osmo_init_logging2(g_tall_ctx, NULL);
|
||||
osmo_fsm_log_timeouts(true);
|
||||
osmo_fsm_log_addr(true);
|
||||
//osmo_stats_init(g_tall_ctx);
|
||||
osmo_rtp_init(g_tall_ctx);
|
||||
|
||||
struct modem_state *ms = modem_create(g_tall_ctx);
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(ms);
|
||||
rc = modem_data_open(ms, "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1");
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
while (1) {
|
||||
osmo_select_main(0);
|
||||
}
|
||||
|
||||
}
|
6
contrib/systemd/Makefile.am
Normal file
6
contrib/systemd/Makefile.am
Normal file
@@ -0,0 +1,6 @@
|
||||
EXTRA_DIST = osmo-mgw.service
|
||||
|
||||
if HAVE_SYSTEMD
|
||||
systemdsystemunit_DATA = \
|
||||
osmo-mgw.service
|
||||
endif
|
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=OpenBSC MGCP
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-bsc_mgcp -s -c /etc/osmocom/osmo-bsc-mgcp.cfg
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
469
debian/changelog
vendored
469
debian/changelog
vendored
@@ -1,3 +1,472 @@
|
||||
osmo-mgw (1.8.1) unstable; urgency=medium
|
||||
|
||||
* attempt to fix RPM spec file after recent soversion bump
|
||||
|
||||
-- Harald Welte <laforge@osmocom.org> Wed, 24 Feb 2021 10:56:17 +0100
|
||||
|
||||
osmo-mgw (1.8.0) unstable; urgency=medium
|
||||
|
||||
[ Harald Welte ]
|
||||
* Fix number of endpoints of default trunk
|
||||
* Add CTRL interface to osmo-mgw
|
||||
* Update per-trunk global packet/byte counters in real-time
|
||||
* remove accidential TODO-RELEASE entry
|
||||
* mgcp_protocol: Avoid code duplication between virtual + other trunks
|
||||
* osmo-mgw.spec.in: Use %config(noreplace) to retain current config file
|
||||
* mgcp_client_init(): consider "talloc returns NULL" case
|
||||
* mgcp_client_pending_add(): Consider "talloc returns NULL" case
|
||||
* libosmo-mgcp-client: fix memleak in case if no response is received
|
||||
* debian/control + SPEC: Add missing build dependency to libosmo-abis
|
||||
* osmo-mgw.spec.in: Fix dependency to libosmoabis
|
||||
* osmo-mgw.spec.in: Add missing dependency to libosmotrau
|
||||
* Add example osmo-mgw configuration file for Abis/E1
|
||||
* use osmo_fd_setup() whenever applicable
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix vty dump_trunk: start from zero, do not omit first CONN
|
||||
* allow larger MGCP client wqueue: 10 -> 1024
|
||||
* add osmo-mgw --vty-ref-xml: dump VTY ref XML to stdout
|
||||
* manuals: generate vty reference xml at build time
|
||||
* refactor: use msgb to receive, pass and send RTP packets
|
||||
* change timer T2427001 to X2427
|
||||
|
||||
[ Philipp Maier ]
|
||||
* doc: do not bind osmo-mgw to random ip-address
|
||||
* cosmetic: remove excess newlines
|
||||
* mgcp: remove unused callback pointer
|
||||
* mgcp: find better locations for LOGPCONN and LOGPENDP
|
||||
* vty: fix unreachable code (error msg on trunk alloc fail)
|
||||
* mgcp_vty: fix indentation
|
||||
* osmo-mgw: rename struct mgcp_trunk_config and symbol tcfg
|
||||
* mgcp_vty: fix indentation in VTY config write
|
||||
* osmo-mgw: refactor endpoint and trunk handling
|
||||
* mgcp_trunk: remove audio_name and audio_payload
|
||||
* ratectr: move rate counter definitions into mgcp_ratectr.h
|
||||
* cosmetic: fix doxygen
|
||||
* cosmetic: fix doxygen
|
||||
* cosmetic: fix doxygen for mgcp_cleanup_rtp_bridge_cb()
|
||||
* trunk: get rid of virt_trunk pointer
|
||||
* cosmetic: remove excess space
|
||||
* endp: move endpoint name generation into mgcp_endp.c
|
||||
* endp: add name generator function for E1 endpoints
|
||||
* mgcp_client: add docstring for mgcp_client_rtpbridge_wildcard()
|
||||
* mgcp_trunk: fix docstring for mgcp_trunk_alloc()
|
||||
* mgcp_osmux: remove unused define constants
|
||||
* mgcp_trunk: move enum mgcp_trunk_type to mgcp_trunk.h
|
||||
* mgcp_trunk: use enum type for trunk type variable
|
||||
* trunk: parse E1 trunk number
|
||||
* endp: add typeset for e1-endpoints
|
||||
* mgcp_conn: move struct mgcp_conn mgcp_conn.h
|
||||
* mgcp_internal: remove forward declaration struct mgcp_endpoint_type
|
||||
* endp: add E1 endpoint interlocking
|
||||
* endp: require domain name also for E1 endpoints
|
||||
* mgcp_trunk: pick trunk by number and type
|
||||
* mgcp_client: add function to generate e1-endpoint names
|
||||
* mgcp_endp: use define constant to define max number of E1 subslots
|
||||
* mgcp_endp.c: cosmetic: fix sourcecode formatting
|
||||
* mgcp_trunk: remove double check
|
||||
* mgcp_test: do not access endpoint array elements directly
|
||||
* mgcp_vty: fix endpoint number configuration
|
||||
* mgcp_test: remove trunk2 from unit-test
|
||||
* mgcp_trunk: use talloc_zero_array instead of _talloc_zero_array
|
||||
* mgcp_protocol: remove unused variable
|
||||
* mgcp_e1: finish E1 support, add E1 support from libosmoabis
|
||||
* get rid of mgcp_internal.h
|
||||
* mgcp_ratectr: fix comments in header file
|
||||
* mgcp_e1: use return value of e1inp_line_update()
|
||||
* mgcp_protocol: log when endpoint is unavailable
|
||||
* cosmetic: add missing new-line
|
||||
* mgcp_trunk: drop "trunk 0" limitation
|
||||
* mgcp_e1: make E1 ts initalization more debugable
|
||||
* mgcp_e1: remove unused struct member trunk->e1.line
|
||||
* mgcp_endp: use NUM_E1_TS from e1_input.h
|
||||
* mgcp_trunk: increase default number of virtual endpoints
|
||||
* cosmetic: mgcp_client_fsm: change error message.
|
||||
* mgcp_vty: remove remains of loopback functionality
|
||||
* mgcp_vty: deprecate bind early command
|
||||
* mgcp_e1: do not expose function mgcp_e1_init()
|
||||
* mgcp_vty: add user attributes to configuration commands
|
||||
* overview: update section limitations.
|
||||
* overview: fix graph "OsmoMGW used with OsmoBSC"
|
||||
* overview: fix graph "OsmoMGW used with OsmoMSC"
|
||||
* overview: add graph to show E1 integration
|
||||
* configuration: remove hint towards trunk 0 limit
|
||||
* configuration: drop note about lackin E1 support
|
||||
* configuration: add note that changes to trunks need a restart
|
||||
* mgcp_vty: fix config write for trunk 0
|
||||
* mgcp_vty: add missing VTY commands for E1 trunks
|
||||
* mgcp_trunk: get rid of magic numbers for E1 slots
|
||||
* configuration: add section about E1 trunks
|
||||
* usermanual: add chapter about mgcp endpoints
|
||||
* mgcp_client: get rid of magic numbers for E1 slots
|
||||
|
||||
[ Eric ]
|
||||
* tests: dlopen does not imply availability of dlsym..
|
||||
* configure.ac: fix libtool issue with clang and sanitizer
|
||||
|
||||
[ Alexander Chemeris ]
|
||||
* vty: Prepend VTY output of counters for better visual separation.
|
||||
* counters: Implement more useful counters.
|
||||
* mgcp_network: Fix a typo in the comment bahviour -> behaviour
|
||||
* rtp_bridge: Demote a chatty ERROR log message to DEBUG level.
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Use OSMO_FD_* instead of deprecated BSC_FD_*
|
||||
* Support setting rt-prio and cpu-affinity mask through VTY
|
||||
* cosmetic: Rename main talloc ctx
|
||||
* mgcp-client: Support IPv6 in osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr() implementation
|
||||
* mgcp-client: Fix trailing whitespace in mgcp_client_fsm.h
|
||||
* mgcp_client: Use INET6_ADDRSTRLEN to store addresses in str format
|
||||
* mgcp_client: Allow submitting and parsing IPv6 addr in SDP
|
||||
* mgcp_client: Allow setting IPv6 addresses
|
||||
* mgcp_client: Make MGCP_CLIENT_LOCAL_ADDR_DEFAULT IPv6 compatible
|
||||
* mgcp_client: Support validating IPv6 addresses in CRCX and MDCX commands
|
||||
* mgcp_client: Deprecate unused IPv4-only API
|
||||
* mgcp_client: copy back Connection Information from MDCX ACK
|
||||
* mgw: Fix mgcp_rtp_end field description comment
|
||||
* mgw: Initial IPv6 support
|
||||
* mgw: Introduce VTY cmd 'rtp bind-ip-v6' command
|
||||
* mgw: Find and store RTP conn local_addr once during CRCX handling
|
||||
* mgw: Announce and rebind new local address if change required during MDCX
|
||||
* mgw: osmux: Avoid sending packets on recvonly connection
|
||||
* mgw: Release endpoint after last conn times out
|
||||
* mgw: osmux: Fix conn watchdog timeout not updated
|
||||
* mgw: Don't be case-sensitive when parsing X-Osmo-IGN param
|
||||
* cosmetic: Fix typo in comment
|
||||
* mgw: Avoid logging notice message each time we receive nt param in LCO
|
||||
* mgw: Fix return value documentation for API mgcp_verify_call_id
|
||||
* cosmetic: Fix typo in comment
|
||||
* contrib/jenkins: Enable parallel make in make distcheck
|
||||
* .gitignore: Ignore new autofoo tmp files
|
||||
* tests: Replace deprecated API log_set_print_filename
|
||||
|
||||
[ Oliver Smith ]
|
||||
* contrib: import RPM spec
|
||||
* contrib: integrate RPM spec
|
||||
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
|
||||
* contrib/jenkins: don't build osmo-gsm-manuals
|
||||
* configure.ac: set -std=gnu11
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* libosmo-mgcp-client: fix use-after-free in mgcp_client_tx()
|
||||
* libosmo-mgcp-client: fix use-after-free in mgcp_msg_gen()
|
||||
* libosmo-mgcp: fix unsigned compared against 0 in mgcp_trunk_by_name()
|
||||
* libosmo-mgcp: fix unused extra argument to printf() in add_fmtp()
|
||||
* libosmo-mgcp: always check result of msgb_printf() in add_fmtp()
|
||||
* libosmo-mgcp-client: mgcp_client_tx(): return rc on error
|
||||
* debian/control: change maintainer to the Osmocom team / mailing list
|
||||
* vty: use install_lib_element() and install_lib_element_ve()
|
||||
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
|
||||
* fixup mgcp_trunk: increase default number of virtual endpoints
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* configure.ac: require libosmoabis + libosmotrau >= 1.0.0
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 18:28:45 +0100
|
||||
|
||||
osmo-mgw (1.7.0) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* rename codecs_cmp() to codecs_same()
|
||||
* mgcp_codec: constify 'param' arg
|
||||
* fix crashes: don't assert on incoming RTP packet size
|
||||
* mgcp_send(): stop looping on conversion error
|
||||
* mgcp_codec: split codec_free() off of codec_init()
|
||||
* fix memleak: actually free strings in mgcp_codec_reset_all()
|
||||
* mgcp_test: extend / rewrite test_mgcp_codec_pt_translate()
|
||||
* test_mgcp_codec_pt_translate(): more tests
|
||||
* differentiate AMR octet-aligned=0 vs =1
|
||||
* ptmap: implicitly match '/8000' and '/8000/1'
|
||||
* mgcp_codec: codec_set(): log about all possible errors
|
||||
* mgcp_codec_add: fix audio_name size check
|
||||
* explicitly free codecs in mgcp_rtp_conn_cleanup()
|
||||
* tweak mgcp_parse_audio_ptime_rtpmap()
|
||||
* SDP: store all ptmap entries
|
||||
* mgcp_client_fsm cleanup: Do not assert on DLCX failure
|
||||
* clear pending requests on MGCP failure
|
||||
* client: endp fsm: add notify struct, prep for cancel-notify
|
||||
* client: endp fsm: clear ci[] before dispatching DLCX success
|
||||
* client: endp fsm: allow cancelling a notify event
|
||||
* client: endp fsm: add osmo_mgcpc_ep_ci_ep()
|
||||
* accept MGCP without SDP
|
||||
* fix use-after-free: require new fsm deferred dealloc, check for term
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mgcp_test: Correctly release all endpoints allocated
|
||||
* mgw: Allocate mgcp_conn instance under tcfg->endpoints
|
||||
|
||||
[ Harald Welte ]
|
||||
* manual: Fix copy+paste error
|
||||
* mgcp_client: Check for osmo_fsm_register() error return value
|
||||
* Move fsm_mgcp_client regstration to __attribute__((contructor))
|
||||
* exit(2) on unsupported positional arguments on command line
|
||||
|
||||
[ Oliver Smith ]
|
||||
* osmoappdesc.py: switch to python 3
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 13:35:09 +0100
|
||||
|
||||
osmo-mgw (1.6.0) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* Cosmetic: fix spaces/tabs in mgcp_requests[]
|
||||
* Inactive connection cleanup (disabled by default)
|
||||
* debian: create -doc subpackage with pdf manuals
|
||||
* vty: allow 0 as conn-timeout to disable it
|
||||
* vty: update desc of conn-timeout
|
||||
* manuals: update VTY documentation
|
||||
* "make dist" fix for: no rule to make mgcp_common.h
|
||||
* contrib/jenkins.sh: run "make maintainer-clean"
|
||||
|
||||
[ Philipp Maier ]
|
||||
* Add option to GSM HR frames to RFC5593 representation
|
||||
* mgcp_sdp: cosmetic: correct typo in comment
|
||||
* mgco_client: cosmetic: remove excess whitespace
|
||||
* mgcp_sdp: mgcp_sdp.c does not include own header file
|
||||
* mgcp_sdp: untangle parsing of a= parameters
|
||||
* mgcp_network: use mgcp_rtp_codec in downlink format callback
|
||||
* AMR: Add function to convert between bw-effient and octet aligned mode
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* log: don't spam with "can not patch PT" messages
|
||||
* mgcp client: allow setting conn mode for CRCX and MDCX
|
||||
* make codec_table public as osmo_mgcpc_codec_names
|
||||
* move MGW endpoint FSM from osmo-bsc to here
|
||||
* fix: multiple initial CRCX
|
||||
* constify map_codec_to_pt() ptmap arg
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mgcp-client: whitespace cleanup in mgcp_client.c
|
||||
* mgcp-client: Sanitize implementation of mgcp_client_rtpbridge_wildcard
|
||||
* libosmo-mgcp: Use trunk type during endpoint allocation
|
||||
* cosmetic: Fix typos in comment
|
||||
* cosmetic: tests: mgcp_client_test: clean trailing whitespace
|
||||
* mgcp_msg: Log faulty line on Osmux parsing error
|
||||
* cosmetic: handle_modify_con: Fix indentation level
|
||||
* Introduce log fmt helpers LOGPENDP and LOGPCONN
|
||||
* create_response_with_sdp: Fix inclusion of X-Osmux
|
||||
* osmux: Cleanup of CID alloc pool APIs
|
||||
* mgcp_osmux.c: osmux_enable_endpoint: Fix incorrect return check
|
||||
* osmux: Log osmux socket during osmux_init
|
||||
* mgcp-cli: Change osmo_mgcpc_ep_fsm name to avoid collision with old osmo-bsc
|
||||
* osmux: Document func and return different rc upon osmux init failure
|
||||
* osmux: Fix reception of legacy dummy payloads
|
||||
* osmux: Use LOGPCONN in several log calls
|
||||
* cosmetic: mgcp_udp_send: Document port param is in network byte order
|
||||
* cosmetic: osmux: Document network byte order in port variable
|
||||
* vty: Allow enabling Osmux
|
||||
* osmux: Allocate CID during CRCX
|
||||
* osmux: Introduce mgcp_conn_rtp_is_osmux() helper
|
||||
* osmux: Mark conn_rtp->type as osmux during CRCX
|
||||
* mgcp-cli: Allow submitting X-Osmux on CRCX request
|
||||
* mgcp-cli: Parse X-Osmux on CRCX response
|
||||
* osmux: Handle Osmux MGCP extension in MDCX messages
|
||||
* mgcp-cli: Allow submitting X-Osmux on MDCX request
|
||||
* mgcp-cli: Parse X-Osmux on MDCX response
|
||||
* osmux: Drop unneeded OSMUX_STATE_NEGOTIATING
|
||||
* mgcp-cli: endpoint_fsm: Add API to retrieve Osmux CID from MGW
|
||||
* osmux: Provide correct local port during mgcp resp
|
||||
* osmux: Use remote port to send osmux frames
|
||||
* osmux: Improve logging around osmux enabling events
|
||||
* osmux: Delay osmux enable of conn until remote addr is configured by MDCX
|
||||
* osmux: Redo read/write osmux glue code to have data routed correctly
|
||||
* mgw, mgcp-li: Handle X-Osmux param name as case insensitive
|
||||
* osmux: Use DUMMY ft msg as per Osmux spec
|
||||
* osmux: Fix loopback for Osmux connections
|
||||
* osmux: Fix CID release for non-enabled connections
|
||||
* osmux: Fix hardcoded rtp payload_type 98 in osmux conn
|
||||
* mgcp-cli: Validate osmux cid value during mgcp_msg_gen
|
||||
* mgw: Support uppercase LCO options
|
||||
* mgw: Support lowercase header parameters
|
||||
* mgcp-cli: Support lowercase header parameters
|
||||
* mgw: Support receiving uppercase connection mode
|
||||
* mgw: Support receiving lowercase LCO codec
|
||||
* mgw: Make check of duplicated LCO fields case insensitive
|
||||
* mgw: Allow receiving lowercase MGCP header keyword
|
||||
* mgw: Allow receiving lowercase X-Osmo-Ign Callid field
|
||||
* mgw: Allow receiving uppercase noanswer keyword
|
||||
* doc: X-Osmo-IGN: small formatting and typo fixes
|
||||
* doc: Add Osmux documentation to OsmoMGW User Manual
|
||||
* Catch unsigned integer MGCP parsing errors with strtoul
|
||||
* Fix return variable of strtoul()
|
||||
* Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
|
||||
* configure.ac: Require libosmo-netif 0.6.0
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* mgcp_internal: LOGPENDP: ensure *endp is not NULL
|
||||
|
||||
[ Harald Welte ]
|
||||
* handle NULL return of rate_ctr_group_alloc()
|
||||
* update .gitignore
|
||||
* mgcp_sdp: Don't check if an unsigned int is below 0
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* configure.ac: drop useless check for -fvisibility=hidden
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* manuals: Add script to regenerate vty/counter documentation
|
||||
* manuals: Update vty/counter documentation
|
||||
|
||||
[ Hoernchen ]
|
||||
* turn -Werror=null-dereference into a warning
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 16:52:58 +0200
|
||||
|
||||
osmo-mgw (1.5.0) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* gitignore: Filter *.pc
|
||||
* configure: Find correct libgsm's gsm.h header
|
||||
* vty: Fix typo writing bts-jitter-buffer-delay-{min,max}
|
||||
* Remove libosmo-legacy-mgcp and osmo-bsc-mgcp
|
||||
* debian: Remove dangling symlink to osmo-bsc-mgcp.service
|
||||
* Install systemd services with autotools
|
||||
* Install sample cfg file to /etc/osmocom
|
||||
* mgcp: Fix osmux_cid_bitmap static array size calculation
|
||||
* mgcp_osmux: Use define to calculate rtp_ssrc_winlen
|
||||
* osmux: Avoid initing output without enabling osmux
|
||||
* mgcp: Log endpoint nr consistently as hex
|
||||
* osmux_send_dummy: Avoid logging incorrectly and sending if osmux not enabled
|
||||
* osmux: Don't process regular osmux frames if disabled by cfg
|
||||
* osmux: Move parse_cid of legacy dummy frames to own function
|
||||
* osmux: Make func handling dummy frames independent of endp type
|
||||
* osmux: allow enabling osmux only on correct activating state
|
||||
* osmux: Improve checks around activating and using enabled osmux
|
||||
* osmux.h: Document enum osmux_state
|
||||
* osmux: Avoid processing further frames if conn not found
|
||||
|
||||
[ Philipp Maier ]
|
||||
* mgcp_client_fsm: allow ptmap in mgcp_client_fsm as well
|
||||
* mgcp_network: translate payload type numbers in RTP packets
|
||||
* mgcp_client: use IETF source port as for MGCP
|
||||
* mgcp_client: increment local port number when port is in use
|
||||
* mgcp_test: release endpoints after use
|
||||
* network: do not patch PT of RTCP packets
|
||||
* network: check packets before further processing
|
||||
* Cosmetic: remove misplaced line break
|
||||
* mgcp_sdp: restructure mgcp_write_response_sdp() (rtpmap)
|
||||
* mgcp_sdp: restructure mgcp_write_response_sdp() (audio)
|
||||
* mgcp_client: check local port only once
|
||||
* mgcp_client_fsm: switch to MGCP_CONN_RECV_SEND in add_audio()
|
||||
* mgcp_protocol: increase buffer space for codec name in LCO
|
||||
* osmo-mgw: Add vty reference manual
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix handling of "Wrong domain name" error
|
||||
* interpret domain '*' as 'allow any domain'
|
||||
* cosmetic: log: fix "CallIDs does not match"
|
||||
* fix 3G hack: allow any IP for loopback and 0.0.0.0
|
||||
* cosmetic: drop code dup in mgcp_client_fsm.c CRCX
|
||||
* add X-Osmo-IGN MGCP header to ignore CallID
|
||||
* X-Osmo-IGN: rather parse items by token, not char
|
||||
* mgcp_test: fix log of conn_id presence
|
||||
* mgcp_test: fix get_conn_id_from_response() CI length
|
||||
* mgcp_client_test: cosmetically re-arrange reply_to() args
|
||||
* mgcp_client_test: use "\r\n\r\n" instead of "\n\n"
|
||||
* mgcp_client_test: also verify received conn_id
|
||||
* mgcp_client_test: test long conn_id
|
||||
* mgcp_client: error on too long conn id
|
||||
* mgcp_common: rename to MGCP_CONN_ID_MAXLEN
|
||||
* doc: fix mgcp_verify_ci() return val doc
|
||||
* mgcp_verify_ci(): return meaningful error codes
|
||||
* fix mgcp_verify_ci(): off-by-one in max len check
|
||||
* generate shorter 'I:' conn IDs
|
||||
* mgcp_conn_get(): compare conn Id ('I:') case insensitively
|
||||
* mgcp_conn_get(): match conn Id ('I:') despite leading zeros
|
||||
* cosmetic: mgcp_test: fix get_conn_id_from_response()
|
||||
* comment: indicate struct type for mgcp_endpoint.conns
|
||||
* log: avoid logging early media as error
|
||||
* fix osmo-mgw -s; fixes osmo-mgw.service using -s
|
||||
* Importing history from osmo-gsm-manuals.git
|
||||
* OsmoMGW: update VTY reference
|
||||
* OsmoMGW: document the 'X-Osmo-IGN' MGCP extension
|
||||
* mgw: update vty reference
|
||||
* drop/replace very weird logging in mgcp_client.c
|
||||
* check_rtp: on IP:port errors, log the IP and port
|
||||
* osmo-mgw: err-log: include expected domain name
|
||||
* mgcp_client_vty: fix missing talloc_free
|
||||
* mgcp_client: drop a bunch of dead code
|
||||
* mgcp_client: logging tweaks
|
||||
* mgcp_client: make domain part of endpoint configurable
|
||||
* mgcp_client: tweak some log levels INFO -> {DEBUG,ERROR}
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* add VTY commands which show specific mgcp endpoints
|
||||
* add MGCP CRCX command statistics to osmo-mgw
|
||||
* show RTP TX/RX stats in 'mgcp show stats' output
|
||||
* use local variable for rate counters in handle_create_con()
|
||||
* add more mgcp crxc error counters
|
||||
* add MDCX command statistics to osmo-mgw
|
||||
* add aggregated rtp connection stats to osmo-mgw
|
||||
* add DLCX command statistics to osmo-mgw
|
||||
|
||||
[ Harald Welte ]
|
||||
* debian/rules: Don't overwrite .tarball-version
|
||||
* check_rtp_origin(): Don't memcmp sockadd_in and in_addr
|
||||
* check_rtp_origin(): Avoid using memcmp for comparing integer types
|
||||
* vty-ref: Update URI of docbook 5.0 schema
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* mgw: Add new VTY reference
|
||||
* Add initial OsmoMGW manual
|
||||
|
||||
[ Oliver Smith ]
|
||||
* build manuals moved here from osmo-gsm-manuals.git
|
||||
* jenkins.sh: remove leftover MGCP env variable
|
||||
* Fix DISTCHECK_CONFIGURE_FLAGS override
|
||||
* contrib/jenkins.sh: build and publish manuals
|
||||
* contrib: fix makedistcheck with disabled systemd
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Sun, 20 Jan 2019 15:02:18 +0100
|
||||
|
||||
osmo-mgw (1.4.0) unstable; urgency=medium
|
||||
|
||||
[ Philipp Maier ]
|
||||
* network: independently initalize state->out_stream
|
||||
* stats: use libosmocore rate counter for in/out_stream.err_ts_counter
|
||||
* mgcp_sdp: correct apidoc of mgcp_parse_sdp_data
|
||||
* vty: clean up rtp port-range command
|
||||
* sdp: remove unused alt_codec field from struct mgcp_rtp_end
|
||||
* sdp: remove circular inclusion
|
||||
* protocol: Try whole port range on port allocation
|
||||
* client: do not start connections in loopback mode
|
||||
* mgcp_network: do not log destination invalid ip/port as error
|
||||
* cosmetic: fix log output
|
||||
* conn: call talloc_free before setting the pointer to NULL
|
||||
* protocol: do not change LCO, when no LCO are present
|
||||
* protocol: reject illegal lco options
|
||||
* cosmetic: fix typo
|
||||
* mgw: clean up codec negotiation (sdp)
|
||||
* client: add features to generate and parse codec information
|
||||
* mgcp_internal: remove unused struct member
|
||||
* stats: replace packet statistic counters with libosmocore rate counters
|
||||
* stat+vty: fix printing of rate counter values
|
||||
* protocol: prevent unnecessary null pointer deref
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* legacy-mgcp: Add jitter buffer on the uplink receiver
|
||||
* legacy-mgcp: switch to new osmux output APIs
|
||||
* mgcp: mgcp_osmux: use conn_bts when forwarding pkts from bsc_nat
|
||||
* mgcp: switch to new osmux output APIs
|
||||
* debian: Package installed example doc files
|
||||
* gitignore: Add m4 scripts from m4 subdir
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* api doc: fix parameter name for mgcp_conn_create()
|
||||
* mgcp-client: add mgcp_conn_get_ci()
|
||||
* mgcp_client_fsm: improve error logging
|
||||
* cosmetic: fix doxygen comment markers
|
||||
* cosmetic: mgcp_network.c: merge one LOGPC to its preceding LOGP
|
||||
* IuUP hack: make RTP patching less general
|
||||
|
||||
[ Harald Welte ]
|
||||
* cosmetic: fix typo in log message: 'abrupt' instead of 'aprupt'
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* git-version-gen: Don't check for .git directory
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 27 Jul 2018 19:05:22 +0200
|
||||
|
||||
osmo-mgw (1.3.0) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
|
40
debian/control
vendored
40
debian/control
vendored
@@ -1,13 +1,15 @@
|
||||
Source: osmo-mgw
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Alexander Couzens <lynxis@fe80.eu>
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Build-Depends: debhelper (>=9),
|
||||
dh-autoreconf,
|
||||
pkg-config,
|
||||
autotools-dev,
|
||||
libosmocore-dev,
|
||||
libosmo-netif-dev
|
||||
libosmocore-dev (>= 1.5.0),
|
||||
libosmo-netif-dev (>= 1.1.0),
|
||||
libosmo-abis-dev (>= 1.1.0),
|
||||
osmo-gsm-manuals-dev (>= 1.1.0)
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
|
||||
Vcs-Browser: https://git.osmocom.org/osmo-mgw/
|
||||
@@ -19,7 +21,7 @@ Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
||||
|
||||
Package: libosmo-mgcp-client3
|
||||
Package: libosmo-mgcp-client8
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
@@ -31,26 +33,14 @@ Package: libosmo-mgcp-client-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: libosmo-mgcp-client3 (= ${binary:Version}), ${misc:Depends}
|
||||
Depends: libosmo-mgcp-client8 (= ${binary:Version}), ${misc:Depends}
|
||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
|
||||
|
||||
Package: osmo-bsc-mgcp
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends: libosmo-legacy-mgcp0, ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: OsmoBSC-MGCP: Osmocom's Legacy Media Gateway; use osmo-mgw instead.
|
||||
|
||||
Package: libosmo-legacy-mgcp0
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Pre-Depends: ${misc:Pre-Depends}
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: libosmo-legacy-mgcp: Osmocom's Legacy Media Gateway server library; use libosmo-mgcp instead.
|
||||
|
||||
Package: libosmo-legacy-mgcp-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: libosmo-legacy-mgcp0 (= ${binary:Version}), ${misc:Depends}
|
||||
Description: libosmo-legacy-mgcp: Osmocom's Legacy Media Gateway server library; use libosmo-mgcp instead.
|
||||
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.
|
||||
|
36
debian/copyright
vendored
36
debian/copyright
vendored
@@ -40,30 +40,6 @@ License: GPL-2.0+
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Files: src/libosmo-legacy-mgcp/g711common.h
|
||||
Copyright: 2000 Abramo Bagnara <abramo@alsa-project.org>
|
||||
License: GPL-2.0+
|
||||
Wrapper for linphone Codec class by Simon Morlat <simon.morlat@linphone.org>
|
||||
.
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
.
|
||||
The FSF address in the above text is the old one.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General Public License
|
||||
Version 2 can be found in `/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
Files: tests/vty_test_runner.py
|
||||
Copyright: 2013 Holger Hans Peter Freyther
|
||||
2013 Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
@@ -87,15 +63,3 @@ License: GPL-3.0+
|
||||
Files: osmoappdesc.py
|
||||
Copyright: 2013 Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
License: GPL-3.0+
|
||||
|
||||
Files: src/libosmo-legacy-mgcp/mgcp_osmux.c
|
||||
Copyright: 2012-2013 On Waves ehf <http://www.on-waves.com>
|
||||
2012-2013 Pablo Neira Ayuso <pablo@gnumonks.org>
|
||||
License: AGPL-3.0+
|
||||
All rights not specifically granted under this license are 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.
|
||||
|
||||
|
4
debian/libosmo-legacy-mgcp-dev.install
vendored
4
debian/libosmo-legacy-mgcp-dev.install
vendored
@@ -1,4 +0,0 @@
|
||||
usr/include/osmocom/legacy_mgcp
|
||||
usr/lib/*/libosmo-legacy-mgcp.so
|
||||
usr/lib/*/libosmo-legacy-mgcp.a
|
||||
usr/lib/*/pkgconfig/libosmo-legacy-mgcp.pc
|
1
debian/libosmo-legacy-mgcp0.install
vendored
1
debian/libosmo-legacy-mgcp0.install
vendored
@@ -1 +0,0 @@
|
||||
usr/lib/*/libosmo-legacy-mgcp.so.*
|
1
debian/osmo-bsc-mgcp.install
vendored
1
debian/osmo-bsc-mgcp.install
vendored
@@ -1 +0,0 @@
|
||||
usr/bin/osmo-bsc_mgcp
|
1
debian/osmo-bsc-mgcp.service
vendored
1
debian/osmo-bsc-mgcp.service
vendored
@@ -1 +0,0 @@
|
||||
../contrib/systemd/osmo-bsc-mgcp.service
|
1
debian/osmo-mgw-doc.install
vendored
Normal file
1
debian/osmo-mgw-doc.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
usr/share/doc/osmo-mgw-doc/*.pdf
|
4
debian/osmo-mgw.install
vendored
4
debian/osmo-mgw.install
vendored
@@ -1 +1,5 @@
|
||||
etc/osmocom/osmo-mgw.cfg
|
||||
lib/systemd/system/osmo-mgw.service
|
||||
usr/bin/osmo-mgw
|
||||
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw.cfg
|
||||
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
|
||||
|
1
debian/osmo-mgw.service
vendored
1
debian/osmo-mgw.service
vendored
@@ -1 +0,0 @@
|
||||
../contrib/systemd/osmo-mgw.service
|
11
debian/rules
vendored
11
debian/rules
vendored
@@ -14,7 +14,7 @@ CFLAGS += -g
|
||||
|
||||
# main packaging script based on dh7 syntax
|
||||
%:
|
||||
dh $@ --with autoreconf
|
||||
dh $@ --with autoreconf
|
||||
|
||||
# debmake generated override targets
|
||||
# Set options for ./configure
|
||||
@@ -29,8 +29,11 @@ CFLAGS += -g
|
||||
override_dh_auto_test:
|
||||
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
|
||||
|
||||
override_dh_autoreconf:
|
||||
echo $(VERSION) > .tarball-version
|
||||
dh_autoreconf
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
|
||||
|
||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
|
||||
override_dh_compress:
|
||||
dh_compress -X.pdf
|
||||
|
||||
# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
|
||||
|
@@ -1,3 +1,4 @@
|
||||
SUBDIRS = \
|
||||
examples \
|
||||
manuals \
|
||||
$(NULL)
|
||||
|
@@ -1,3 +1,11 @@
|
||||
OSMOCONF_FILES = \
|
||||
osmo-mgw/osmo-mgw.cfg
|
||||
|
||||
osmoconfdir = $(sysconfdir)/osmocom
|
||||
osmoconf_DATA = $(OSMOCONF_FILES)
|
||||
|
||||
EXTRA_DIST = $(OSMOCONF_FILES)
|
||||
|
||||
CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,'
|
||||
|
||||
dist-hook:
|
||||
|
@@ -1,14 +0,0 @@
|
||||
!
|
||||
! MGCP configuration example
|
||||
!
|
||||
mgcp
|
||||
!local ip 10.23.24.2
|
||||
!bts ip 10.24.24.1
|
||||
!bind ip 10.23.24.1
|
||||
bind port 2427
|
||||
rtp base 4000
|
||||
rtp force-ptime 20
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name AMR/8000
|
||||
number endpoints 31
|
||||
no rtcp-omit
|
25
doc/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
Normal file
25
doc/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
Normal file
@@ -0,0 +1,25 @@
|
||||
!
|
||||
! MGCP configuration example
|
||||
!
|
||||
e1_input
|
||||
e1_line 0 driver dahdi
|
||||
e1_line 0 port 0
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 512
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
rtp-patch ssrc
|
||||
rtp-patch timestamp
|
||||
trunk 1
|
||||
rtp keep-alive once
|
||||
no rtp keep-alive
|
||||
line 0
|
@@ -4,13 +4,13 @@
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp bind-ip 10.9.1.122
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp ip-probing
|
||||
rtp ip-tos 184
|
||||
rtp ip-dscp 46
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 31
|
||||
number endpoints 512
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
|
23
doc/manuals/Makefile.am
Normal file
23
doc/manuals/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
EXTRA_DIST = osmomgw-usermanual.adoc \
|
||||
osmomgw-usermanual-docinfo.xml \
|
||||
osmomgw-vty-reference.xml \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
if BUILD_MANUALS
|
||||
ASCIIDOC = osmomgw-usermanual.adoc
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||
|
||||
VTY_REFERENCE = osmomgw-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
BUILT_REFERENCE_XML = $(builddir)/vty/mgw_vty_reference.xml
|
||||
$(builddir)/vty/mgw_vty_reference.xml: $(top_builddir)/src/osmo-mgw/osmo-mgw
|
||||
mkdir -p $(builddir)/vty
|
||||
$(top_builddir)/src/osmo-mgw/osmo-mgw --vty-ref-xml > $@
|
||||
|
||||
OSMO_REPOSITORY = osmo-mgw
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
|
||||
endif
|
124
doc/manuals/chapters/configuration.adoc
Normal file
124
doc/manuals/chapters/configuration.adoc
Normal file
@@ -0,0 +1,124 @@
|
||||
== Configuring OsmoMGW
|
||||
|
||||
A basic configation of OsmoMGW mainly consists of specifying the IP address
|
||||
and port on which to listen to MGCP commands, but changing the port range at
|
||||
which the RTP streams terminate as well as limiting operation to a single call
|
||||
agent can be done as well as changing the number of endpoints.
|
||||
|
||||
=== Configuring MGCP
|
||||
|
||||
By default OsmoMGW listens for MGCP on port 2427 on any IP address. If a call
|
||||
agent address is configured then OsmoMGW will only answer MGCP commands from
|
||||
that IP port 2727, otherwise all sources are handled. A domain can be
|
||||
specified
|
||||
|
||||
.Example: MGCP configuration
|
||||
----
|
||||
OsmoMGW(config-mgcp)# bind ip 127.0.0.1
|
||||
OsmoMGW(config-mgcp)# bind port 2427
|
||||
OsmoMGW(config-mgcp)# call-agent ip 127.0.0.1
|
||||
OsmoMGW(config-mgcp)# domain mgw-bsc
|
||||
OsmoMGW(config-mgcp)# local ip 127.0.0.1
|
||||
----
|
||||
|
||||
=== Configuring the trunk
|
||||
|
||||
The first trunk is considered a virtual trunk in OsmoMGW. All
|
||||
endpoints of type "rtpbridge" are routed here. The virtual trunk is configured
|
||||
in the config-mgcp context.
|
||||
|
||||
All other trunks are configured in the config-mgcp-trunk context, but the
|
||||
commands used are identical. Right now trunks are considered only for "ds/e1"
|
||||
type endpoints.
|
||||
|
||||
.Example: MGCP trunk configuration
|
||||
----
|
||||
OsmoMGW(config-mgcp)# number endpoints 63 <1>
|
||||
OsmoMGW(config-mgcp)# rtp bind-ip 10.0.0.1 <2>
|
||||
OsmoMGW(config-mgcp)# rtp port-range 12000-14000 <3>
|
||||
----
|
||||
<1> Maximum number of endpoints that can be allocated at once
|
||||
<2> Use this IP when binding RTP endpoints
|
||||
<3> Use ports in this range when binding RTP endpoints
|
||||
|
||||
There are some options to tweak how RTP forwarding behaves in OsmoMGW:
|
||||
|
||||
.Example: MGCP trunk rtp options
|
||||
----
|
||||
OsmoMGW(config-mgcp)# rtp keep-alive 30 <1>
|
||||
OsmoMGW(config-mgcp)# rtp-patch ssrc <2>
|
||||
OsmoMGW(config-mgcp)# rtp-patch timestamp <3>
|
||||
----
|
||||
<1> Send dummy UDP packets periodically to RTP destination
|
||||
<2> Hide SSRC changes
|
||||
<3> Ensure RTP timestamp is aligned with frame duration
|
||||
|
||||
NOTE: Changes to trunks that affect resource allocation, such as newly created
|
||||
trunks or a change of the number of available endpoints, require a full restart
|
||||
of osmo-mgw!
|
||||
|
||||
=== E1 trunk considerations
|
||||
|
||||
While the RTP bridge trunks are natively based on IP no special considerations
|
||||
are required during setup. E1 trunks are mapped on a physical E1 line, which has
|
||||
to be configured as shown below.
|
||||
|
||||
.Example: E1 line setup
|
||||
----
|
||||
OsmoMGW(config-e1_input)# e1_line 0 driver dahdi <1>
|
||||
OsmoMGW(config-e1_input)# e1_line 0 port 2 <2>
|
||||
----
|
||||
<1> Name of the libosmo-abis driver implementation ("dahdi")
|
||||
<2> Port number of the physical E1 port to use (2)
|
||||
|
||||
In osmo-mgw the e1_input node is used to configure the physical E1 line. The
|
||||
line number will be used internally to identify the configured E1 line. The
|
||||
port number is the physical E1 connector (sometimes called 'span') at the E1
|
||||
hardware. Per trunk an individual E1 line will be needed. Beware that the E1
|
||||
driver may also need configuration settings that are not discussed here.
|
||||
|
||||
.Example: E1 trunk setup
|
||||
----
|
||||
OsmoMGW(config-mgcp)# trunk 0 <1>
|
||||
OsmoMGW(config-mgcp-trunk)# line 0 <2>
|
||||
----
|
||||
<1> Creation of a trunk (0)
|
||||
<2> Reference to the E1 line to use (0)
|
||||
|
||||
The E1 trunk is created along with a number, typically starting at 0, but if
|
||||
required any number from 0-64 is allowed. The E1 trunk configuration concerning
|
||||
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
|
||||
that were configured under the e1_input node.
|
||||
|
||||
.Example: A typical configuration with one E1 trunk
|
||||
----
|
||||
e1_input
|
||||
e1_line 0 driver dahdi
|
||||
e1_line 0 port 2
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp net-range 6000 6011
|
||||
rtp net-bind-ip 192.168.100.130
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
no rtp keep-alive
|
||||
bind port 2428
|
||||
number endpoints 30
|
||||
loop 0
|
||||
force-realloc 1
|
||||
osmux off
|
||||
rtp-patch rfc5993hr
|
||||
trunk 0
|
||||
rtp keep-alive once
|
||||
no rtp keep-alive
|
||||
line 0
|
||||
----
|
||||
|
||||
NOTE: One E1 trunk always covers a whole E1 line. All subslots (I.640) will be mapped
|
||||
to individual MGCP endpoints. As long as the endpoints remain unused the
|
||||
underlying E1 timeslot is not used.
|
||||
|
||||
NOTE: The E1 trunk implementation also works with T1 lines, however since T1 has
|
||||
24 instead of 31 usable timeslots only the endpoints that fall into that 1-24 timeslot
|
||||
range will be useable.
|
4
doc/manuals/chapters/counters.adoc
Normal file
4
doc/manuals/chapters/counters.adoc
Normal file
@@ -0,0 +1,4 @@
|
||||
[[counters]]
|
||||
== Counters
|
||||
|
||||
include::./counters_generated.adoc[]
|
83
doc/manuals/chapters/counters_generated.adoc
Normal file
83
doc/manuals/chapters/counters_generated.adoc
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
// autogenerated by show asciidoc counters
|
||||
These counters and their description based on OsmoMGW 1.5.0.64-189f (OsmoMGW).
|
||||
|
||||
=== Rate Counters
|
||||
|
||||
// generating tables for rate_ctr_group
|
||||
// rate_ctr_group table aggregated statistics for all rtp connections
|
||||
.all_rtp_conn - aggregated statistics for all rtp connections
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| all_rtp:err_tstmp_in | <<all_rtp_conn_all_rtp:err_tstmp_in>> | Total inbound rtp-stream timestamp errors.
|
||||
| all_rtp:err_tstmp_out | <<all_rtp_conn_all_rtp:err_tstmp_out>> | Total outbound rtp-stream timestamp errors.
|
||||
| all_rtp:packets_rx | <<all_rtp_conn_all_rtp:packets_rx>> | Total inbound rtp packets.
|
||||
| all_rtp:octets_rx | <<all_rtp_conn_all_rtp:octets_rx>> | Total inbound rtp octets.
|
||||
| all_rtp:packets_tx | <<all_rtp_conn_all_rtp:packets_tx>> | Total outbound rtp packets.
|
||||
| all_rtp:octets_tx | <<all_rtp_conn_all_rtp:octets_tx>> | Total outbound rtp octets.
|
||||
| all_rtp:dropped | <<all_rtp_conn_all_rtp:dropped>> | Total dropped rtp packets.
|
||||
| all_rtp:num_closed_conns | <<all_rtp_conn_all_rtp:num_closed_conns>> | Total number of rtp connections closed.
|
||||
|===
|
||||
// rate_ctr_group table dlcx statistics
|
||||
.dlcx - dlcx statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| dlcx:success | <<dlcx_dlcx:success>> | DLCX command processed successfully.
|
||||
| dlcx:wildcard | <<dlcx_dlcx:wildcard>> | wildcard names in DLCX commands are unsupported.
|
||||
| dlcx:no_conn | <<dlcx_dlcx:no_conn>> | endpoint specified in DLCX command has no active connections.
|
||||
| dlcx:callid | <<dlcx_dlcx:callid>> | CallId specified in DLCX command mismatches endpoint's CallId .
|
||||
| dlcx:connid | <<dlcx_dlcx:connid>> | connection ID specified in DLCX command does not exist on endpoint.
|
||||
| dlcx:unhandled_param | <<dlcx_dlcx:unhandled_param>> | unhandled parameter in DLCX command.
|
||||
| dlcx:rejected | <<dlcx_dlcx:rejected>> | connection deletion rejected by policy.
|
||||
| dlcx:deferred | <<dlcx_dlcx:deferred>> | connection deletion deferred by policy.
|
||||
|===
|
||||
// rate_ctr_group table mdcx statistics
|
||||
.mdcx - mdcx statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| mdcx:success | <<mdcx_mdcx:success>> | MDCX command processed successfully.
|
||||
| mdcx:wildcard | <<mdcx_mdcx:wildcard>> | wildcard endpoint names in MDCX commands are unsupported.
|
||||
| mdcx:no_conn | <<mdcx_mdcx:no_conn>> | endpoint specified in MDCX command has no active connections.
|
||||
| mdcx:callid | <<mdcx_mdcx:callid>> | invalid CallId specified in MDCX command.
|
||||
| mdcx:connid | <<mdcx_mdcx:connid>> | invalid connection ID specified in MDCX command.
|
||||
| crcx:unhandled_param | <<mdcx_crcx:unhandled_param>> | unhandled parameter in MDCX command.
|
||||
| mdcx:no_connid | <<mdcx_mdcx:no_connid>> | no connection ID specified in MDCX command.
|
||||
| mdcx:conn_not_found | <<mdcx_mdcx:conn_not_found>> | connection specified in MDCX command does not exist.
|
||||
| mdcx:invalid_mode | <<mdcx_mdcx:invalid_mode>> | invalid connection mode in MDCX command.
|
||||
| mdcx:conn_opt | <<mdcx_mdcx:conn_opt>> | connection options invalid.
|
||||
| mdcx:no_remote_conn_desc | <<mdcx_mdcx:no_remote_conn_desc>> | no opposite end specified for connection.
|
||||
| mdcx:start_rtp_failure | <<mdcx_mdcx:start_rtp_failure>> | failure to start RTP processing.
|
||||
| mdcx:conn_rejected | <<mdcx_mdcx:conn_rejected>> | connection rejected by policy.
|
||||
| mdcx:conn_deferred | <<mdcx_mdcx:conn_deferred>> | connection deferred by policy.
|
||||
|===
|
||||
// rate_ctr_group table crxc statistics
|
||||
.crcx - crxc statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| crcx:success | <<crcx_crcx:success>> | CRCX command processed successfully.
|
||||
| crcx:bad_action | <<crcx_crcx:bad_action>> | bad action in CRCX command.
|
||||
| crcx:unhandled_param | <<crcx_crcx:unhandled_param>> | unhandled parameter in CRCX command.
|
||||
| crcx:missing_callid | <<crcx_crcx:missing_callid>> | missing CallId in CRCX command.
|
||||
| crcx:invalid_mode | <<crcx_crcx:invalid_mode>> | invalid connection mode in CRCX command.
|
||||
| crcx:limit_exceeded | <<crcx_crcx:limit_exceeded>> | limit of concurrent connections was reached.
|
||||
| crcx:unkown_callid | <<crcx_crcx:unkown_callid>> | unknown CallId in CRCX command.
|
||||
| crcx:alloc_conn_fail | <<crcx_crcx:alloc_conn_fail>> | connection allocation failure.
|
||||
| crcx:no_remote_conn_desc | <<crcx_crcx:no_remote_conn_desc>> | no opposite end specified for connection.
|
||||
| crcx:start_rtp_failure | <<crcx_crcx:start_rtp_failure>> | failure to start RTP processing.
|
||||
| crcx:conn_rejected | <<crcx_crcx:conn_rejected>> | connection rejected by policy.
|
||||
| crcx:no_osmux | <<crcx_crcx:no_osmux>> | no osmux offered by peer.
|
||||
| crcx:conn_opt | <<crcx_crcx:conn_opt>> | connection options invalid.
|
||||
| crcx:codec_nego | <<crcx_crcx:codec_nego>> | codec negotiation failure.
|
||||
| crcx:bind_port | <<crcx_crcx:bind_port>> | port bind failure.
|
||||
|===
|
||||
== Osmo Stat Items
|
||||
|
||||
// generating tables for osmo_stat_items
|
||||
== Osmo Counters
|
||||
|
||||
// generating tables for osmo_counters
|
||||
// there are no ungrouped osmo_counters
|
94
doc/manuals/chapters/mgcp_endpoints.adoc
Normal file
94
doc/manuals/chapters/mgcp_endpoints.adoc
Normal file
@@ -0,0 +1,94 @@
|
||||
== MGCP Endpoints
|
||||
|
||||
MGCP organizes the switching resources in so called endpoints. Each endpoint is
|
||||
referenced by its unique identifier. While RFC 3435 specifies a naming scheme, the
|
||||
actual identifier naming is subject to the implementation and configuration.
|
||||
|
||||
=== RTP proxy / RTP bridge endpoints
|
||||
|
||||
OsmoMGW implements a freely configurable number of `rtpbridge` endpoints. Those
|
||||
endpoints are able to host two connections at a time to model the functionality
|
||||
of a tandem switch.
|
||||
|
||||
RTP bridge endpoint identifiers are referenced by the string `rtpbridge/`, a
|
||||
hexadecimal number without leading zeros and a domain name (configurable).
|
||||
|
||||
----
|
||||
rtpbridge/<number>@<domain>
|
||||
----
|
||||
|
||||
.Example: List of virtual endpoints
|
||||
----
|
||||
rtpbridge/1@mgw
|
||||
rtpbridge/2@mgw
|
||||
rtpbridge/3@mgw
|
||||
rtpbridge/4@mgw
|
||||
rtpbridge/5@mgw
|
||||
rtpbridge/6@mgw
|
||||
rtpbridge/7@mgw
|
||||
rtpbridge/8@mgw
|
||||
rtpbridge/9@mgw
|
||||
rtpbridge/a@mgw
|
||||
rtpbridge/b@mgw
|
||||
rtpbridge/c@mgw
|
||||
rtpbridge/d@mgw
|
||||
rtpbridge/e@mgw
|
||||
rtpbridge/f@mgw
|
||||
rtpbridge/10@mgw
|
||||
----
|
||||
|
||||
=== E1/T1 endpoints
|
||||
|
||||
OsmoMGW supports E1 subslot multiplexing as specified by I.460. All possible
|
||||
subslot combinations are mapped on individual endpoints. The endpoint names
|
||||
are prefixed with `ds/e1-` followed by the trunk number and the E1 timeslot.
|
||||
The subslot is defined by a bit rate and a bit offset.
|
||||
|
||||
----
|
||||
ds/e1-<trunk>/s-<timeslot>/su<bitrate>-<bitoffset>@<domain>
|
||||
----
|
||||
|
||||
.Example: List of endpoints on E1 trunk 0 at E1 timeslot 2
|
||||
----
|
||||
ds/e1-0/s-2/su64-0@mgw
|
||||
ds/e1-0/s-2/su32-0@mgw
|
||||
ds/e1-0/s-2/su32-4@mgw
|
||||
ds/e1-0/s-2/su16-0@mgw
|
||||
ds/e1-0/s-2/su16-2@mgw
|
||||
ds/e1-0/s-2/su16-4@mgw
|
||||
ds/e1-0/s-2/su16-6@mgw
|
||||
ds/e1-0/s-2/su8-0@mgw
|
||||
ds/e1-0/s-2/su8-1@mgw
|
||||
ds/e1-0/s-2/su8-2@mgw
|
||||
ds/e1-0/s-2/su8-3@mgw
|
||||
ds/e1-0/s-2/su8-4@mgw
|
||||
ds/e1-0/s-2/su8-5@mgw
|
||||
ds/e1-0/s-2/su8-6@mgw
|
||||
ds/e1-0/s-2/su8-7@mgw
|
||||
----
|
||||
|
||||
When creating connections on endpoints that reside in one E1 timeslot the call
|
||||
agent must make sure that no overlapping endpoints are used. It is for example
|
||||
not possible to use `ds/e1-0/s-2/su16-2@mgw` and `ds/e1-0/s-2/su8-3@mgw` at the
|
||||
same time because they overlap.
|
||||
|
||||
.Subslot overlapping
|
||||
[options="header"]
|
||||
|===
|
||||
| Bit offset 4+| Subslots
|
||||
| 0 | 8k .2+| 16k .4+| 32k .8+| 64k
|
||||
| 1 | 8k
|
||||
| 2 | 8k .2+| 16k
|
||||
| 3 | 8k
|
||||
| 4 | 8k .2+| 16k .4+| 32k
|
||||
| 5 | 8k
|
||||
| 6 | 8k .2+| 16k
|
||||
| 7 | 8k
|
||||
|===
|
||||
|
||||
NOTE: The current implementation (December 2020) only implements TRAU frame
|
||||
encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
|
||||
not yet useable.
|
||||
|
||||
NOTE: the VTY command "show mgcp" can be used to get a list of all available
|
||||
endpoints (including identifiers)
|
72
doc/manuals/chapters/mgcp_extensions.adoc
Normal file
72
doc/manuals/chapters/mgcp_extensions.adoc
Normal file
@@ -0,0 +1,72 @@
|
||||
== MGCP Extensions
|
||||
|
||||
The MGCP protocol is extendable. The following non-standard extensions are
|
||||
understood by OsmoMGW.
|
||||
|
||||
=== `X-Osmo-IGN`
|
||||
|
||||
`X-Osmo-IGN` indicates to OsmoMGW that specific items of an endpoint should be
|
||||
ignored, so that it is lenient on mismatching values that would normally
|
||||
indicate collisions or configuration errors.
|
||||
|
||||
==== `X-Osmo-IGN` Format
|
||||
|
||||
The value part of `X-Osmo-IGN` must be one or more items separated by one or more
|
||||
spaces. Each item consists of one or more non-whitespace characters.
|
||||
|
||||
.Example: `X-Osmo-IGN` format with three ficticious items "X", "abc" and "123".
|
||||
----
|
||||
X-Osmo-IGN: X abc 123
|
||||
----
|
||||
|
||||
`X-Osmo-IGN` must be issued in the MGCP header section (typically as its last item),
|
||||
before the SDP section starts.
|
||||
|
||||
==== Supported `X-Osmo-IGN` Items
|
||||
|
||||
Currently, the following `X-Osmo-IGN` items are supported:
|
||||
|
||||
* `C`: ignore CallID mismatches, i.e. differing "C" values between connections
|
||||
on the same endpoint.
|
||||
|
||||
.Note:
|
||||
`X-Osmo-IGN` does not support ignoring mismatches on the domain part of
|
||||
an endpoint name, e.g. ignoring a mismatch on "example.com" in
|
||||
`rtpbridge/123abc@example.com`. Instead, you may globally configure OsmoMGW
|
||||
with `mgcp` / `domain *` to permit all domain parts.
|
||||
|
||||
===== `X-Osmo-IGN: C`
|
||||
|
||||
By default, OsmoMGW verifies that all CallIDs ("C" values) match for all
|
||||
connections on any one given endpoint. To ignore CallID mismatches, pass a `C`
|
||||
in the `X-Osmo-IGN` header, for the first or the second `CRCX` on an endpoint.
|
||||
When the `X-Osmo-IGN: C` is sent for any one `CRCX` on an endpoint, CallID
|
||||
mismatches will be ignored for that and all subsequent messages for that
|
||||
endpoint. Hence this header only needs to be included once per endpoint, in any
|
||||
`CRCX` message that precedes or coincides with a CallID mismatch.
|
||||
|
||||
This is particularly useful for a BSC that is connected to an A/SCCPlite MSC,
|
||||
where the BSC and MSC each are expected to configure their respective own
|
||||
connection on a shared endpoint. For A/SCCPlite, it is impossible for the BSC
|
||||
to know the CallID that the MSC will use, so CallID mismatches are inevitable.
|
||||
See also OsmoBSC, which will by default pass the `X-Osmo-IGN: C` header for
|
||||
endpoints associated with an A/SCCPlite MSC.
|
||||
|
||||
.Example: `CRCX` message that instructs OsmoMGW to ignore CallID mismatches
|
||||
----
|
||||
CRCX 2 rtpbridge/123abc@mgw MGCP 1.0
|
||||
M: recvonly
|
||||
C: 2
|
||||
L: p:20
|
||||
X-Osmo-IGN: C
|
||||
|
||||
v=0
|
||||
c=IN IP4 123.12.12.123
|
||||
m=audio 5904 RTP/AVP 97
|
||||
a=rtpmap:97 GSM-EFR/8000
|
||||
a=ptime:40
|
||||
----
|
||||
|
||||
=== `X-Osmux`
|
||||
|
||||
See <<mgcp-extension-osmux>>
|
115
doc/manuals/chapters/overview.adoc
Normal file
115
doc/manuals/chapters/overview.adoc
Normal file
@@ -0,0 +1,115 @@
|
||||
[[overview]]
|
||||
== Overview
|
||||
|
||||
This manual should help you getting started with OsmoMGW. It will cover
|
||||
aspects of configuring and running the media gateway.
|
||||
|
||||
[[intro_overview]]
|
||||
=== About OsmoMGW
|
||||
|
||||
OsmoMGW is the Osmocom implementation of a media gateway to handle user
|
||||
plane (voice) traffic in cellular networks. It can connect and optionally
|
||||
transcode RTP voice streams between different network elements such as BTSs
|
||||
and external entities like SIP. It is typically co-located with both OsmoBSC
|
||||
and OsmoMSC and controlled by them via MGCP, the Media Gateway Control
|
||||
Protocol.
|
||||
|
||||
[[fig-bsc]]
|
||||
.OsmoMGW used with OsmoBSC
|
||||
[graphviz]
|
||||
----
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
OsmoBTS -> OsmoBSC [label="Abis/IP"];
|
||||
OsmoBSC -> "core-network" [label="3GPP AoIP"];
|
||||
OsmoBSC -> OsmoMGW [label="MGCP"];
|
||||
OsmoBTS -> OsmoMGW [label="RTP",dir=both];
|
||||
OsmoMGW -> "core-network" [label="RTP",dir=both];
|
||||
{rank=same OsmoBSC OsmoMGW}
|
||||
OsmoMGW [color=red];
|
||||
}
|
||||
----
|
||||
|
||||
[[fig-msc]]
|
||||
.OsmoMGW used with OsmoMSC
|
||||
[graphviz]
|
||||
----
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
"2G BSS" -> OsmoMSC [label="3GPP AoIP"];
|
||||
OsmoMSC -> OsmoMGW [label="MGCP"];
|
||||
"2G BSS" -> OsmoMGW [label="RTP",dir=both];
|
||||
OsmoMSC -> OsmoSIP [label="MNCC"];
|
||||
OsmoSIP -> PBX [label="SIP Trunk"];
|
||||
OsmoMGW -> PBX [label="RTP",dir=both];
|
||||
{rank=same OsmoMSC OsmoMGW}
|
||||
OsmoSIP [label="osmo-sip-connector"];
|
||||
OsmoMGW [color=red];
|
||||
|
||||
hNodeB -> OsmoHNBGW [label="Iuh"];
|
||||
OsmoHNBGW -> OsmoMSC [label="IuCS"];
|
||||
hNodeB -> OsmoMGW [label="RTP",dir=both];
|
||||
}
|
||||
----
|
||||
|
||||
[[fig-bsc-e1]]
|
||||
.Integration of legacy E1 BTS in AoIP network
|
||||
[graphviz]
|
||||
----
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
BTS -> OsmoBSC [label="Abis/E1"];
|
||||
OsmoBSC -> "core-network" [label="3GPP AoIP"];
|
||||
OsmoBSC -> OsmoMGW [label="MGCP"];
|
||||
BTS -> OsmoMGW [label="TRAU/E1",dir=both];
|
||||
OsmoMGW -> "core-network" [label="RTP",dir=both];
|
||||
{rank=same OsmoBSC OsmoMGW}
|
||||
OsmoMGW [color=red];
|
||||
}
|
||||
----
|
||||
|
||||
=== Software Components
|
||||
|
||||
OsmoMGW contains a variety of different software components, which we’ll
|
||||
quickly describe in this section.
|
||||
|
||||
==== MGCP Implementation
|
||||
|
||||
OsmoMGW brings its own MGCP implementation through which OsmoMGW is
|
||||
controlled.
|
||||
|
||||
The commands implemented are CRCX, MDCX, DLCX and RSIP. The command AUEP is
|
||||
implemented as a stub and will simply respond with OK.
|
||||
|
||||
==== RTP implementation
|
||||
|
||||
Support for IuUP which is used in 3G cells is quite lacking at the moment.
|
||||
3G<->3G and 2G<->2G calls should work, but 3G<->2G does not.
|
||||
|
||||
==== Audio transcoder
|
||||
|
||||
Transcoding is currently not supported in OsmoMGW.
|
||||
|
||||
=== Limitations
|
||||
|
||||
At the moment (November 2020), OsmoMGW implements RTP proxy / RTP bridge
|
||||
type endpoints and E1/T1 16k/8k sub-slots with TRAU frames for classic BTS
|
||||
support. To the RTP proxy / RTP bridge endpoints two RTP connections can
|
||||
be established, which then work as a tandem. E1/T1 endpoints support one
|
||||
RTP connection at a time that is associated with a sub-slot on an E1 line.
|
||||
We are planning to add further endpoint types for:
|
||||
|
||||
- classic E1/T1 timeslots (64kBps alaw/ulaw)
|
||||
- announcement/playout end-points
|
||||
- conference endpoints
|
||||
|
||||
=== Additional resources
|
||||
|
||||
You can find the OsmoMGW issue tracker and wiki online at
|
||||
|
||||
- https://osmocom.org/projects/osmomgw
|
||||
- https://osmocom.org/projects/osmomgw/wiki
|
||||
|
||||
RFC 3435 for MGCP is located at
|
||||
|
||||
- https://tools.ietf.org/html/rfc3435
|
42
doc/manuals/chapters/qos-example.adoc
Normal file
42
doc/manuals/chapters/qos-example.adoc
Normal file
@@ -0,0 +1,42 @@
|
||||
==== Full example of QoS for osmo-mgw
|
||||
|
||||
In the below example we will show the full set of configuration required
|
||||
for both DSCP and PCP differentiation of RTP traffic by osmo-mgw.
|
||||
|
||||
What we want to achieve in this example is the following configuration:
|
||||
|
||||
.DSCP and PCP assignments for osmo-mgw Abis downlink traffic in this example
|
||||
[options="header",width="30%",cols="2,1,1"]
|
||||
|===
|
||||
|Traffic |DSCP|PCP
|
||||
|RTP | 46| 6
|
||||
|===
|
||||
|
||||
. configure the osmo-mgw program to set the DSCP value
|
||||
. configure an egrees QoS map to map from priority to PCP
|
||||
|
||||
.Example Step 1: add related VTY configuration to `osmo-mgw.cfg`
|
||||
----
|
||||
...
|
||||
mgcp
|
||||
rtp ip-dscp 46
|
||||
rtp socket-priority 6
|
||||
...
|
||||
----
|
||||
|
||||
.Example Step 2: egress QoS map to map from socket priority to PCP values
|
||||
----
|
||||
$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 5:5 6:6 7:7 <2>
|
||||
----
|
||||
<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
|
||||
<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also include the
|
||||
mapping 5:5 and 7:7 from the osmo-bsc example (see <<userman-osmobsc>>) here.
|
||||
|
||||
NOTE:: The settings of the `ip` command are volatile and only active until
|
||||
the next reboot (or the network device or VLAN is removed). Please refer to
|
||||
the documentation of your specific Linux distribution in order to find out how
|
||||
to make such settings persistent by means of an `ifup` hook whenever the interface
|
||||
comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
|
||||
script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu,
|
||||
this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
|
||||
script.
|
25
doc/manuals/chapters/running.adoc
Normal file
25
doc/manuals/chapters/running.adoc
Normal file
@@ -0,0 +1,25 @@
|
||||
== Running OsmoMGW
|
||||
|
||||
The OsmoMGW executable (`osmo-mgw`) offers the following command-line
|
||||
arguments:
|
||||
|
||||
=== SYNOPSIS
|
||||
|
||||
*osmo-mgw* [-h|-V] [-D] [-c 'CONFIGFILE'] [-s]
|
||||
|
||||
=== OPTIONS
|
||||
|
||||
*-h, --help*::
|
||||
Print a short help message about the supported options
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the program
|
||||
*-D, --daemonize*::
|
||||
Fork the process as a daemon into background.
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
Specify the file and path name of the configuration file to be
|
||||
used. If none is specified, use `osmo-mgw.cfg` in the current
|
||||
working directory.
|
||||
*-s, --disable-color*::
|
||||
Disable colors for logging to stderr. This has mostly been
|
||||
deprecated by VTY based logging configuration, see <<logging>>
|
||||
for more information.
|
47
doc/manuals/osmomgw-usermanual-docinfo.xml
Normal file
47
doc/manuals/osmomgw-usermanual-docinfo.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>1</revnumber>
|
||||
<date>July 24th, 2018</date>
|
||||
<authorinitials>DW</authorinitials>
|
||||
<revremark>
|
||||
Initial version
|
||||
</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Daniel</firstname>
|
||||
<surname>Willmann</surname>
|
||||
<email>dwillmann@sysmocom.de</email>
|
||||
<authorinitials>DW</authorinitials>
|
||||
<affiliation>
|
||||
<shortaffil>sysmocom</shortaffil>
|
||||
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2018</year>
|
||||
<holder>sysmocom - s.f.m.c. GmbH</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>
|
||||
Permission is granted to copy, distribute and/or modify this
|
||||
document under the terms of the GNU Free Documentation License,
|
||||
Version 1.3 or any later version published by the Free Software
|
||||
Foundation; with the Invariant Sections being just 'Foreword',
|
||||
'Acknowledgements' and 'Preface', with no Front-Cover Texts,
|
||||
and no Back-Cover Texts. A copy of the license is included in
|
||||
the section entitled "GNU Free Documentation License".
|
||||
</para>
|
||||
<para>
|
||||
The Asciidoc source code of this manual can be found at
|
||||
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
|
||||
http://git.osmocom.org/osmo-gsm-manuals/
|
||||
</ulink>
|
||||
</para>
|
||||
</legalnotice>
|
||||
|
39
doc/manuals/osmomgw-usermanual.adoc
Normal file
39
doc/manuals/osmomgw-usermanual.adoc
Normal file
@@ -0,0 +1,39 @@
|
||||
:gfdl-enabled:
|
||||
:program-name: OsmoMGW
|
||||
|
||||
OsmoMGW User Manual
|
||||
====================
|
||||
Daniel Willmann <dwillmann@sysmocom.de>
|
||||
|
||||
|
||||
include::./common/chapters/preface.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/overview.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/running.adoc[]
|
||||
|
||||
include::./common/chapters/vty.adoc[]
|
||||
|
||||
include::./common/chapters/logging.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/configuration.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/mgcp_endpoints.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/mgcp_extensions.adoc[]
|
||||
|
||||
include::./common/chapters/osmux/osmux.adoc[]
|
||||
|
||||
include::./common/chapters/qos-dscp-pcp.adoc[]
|
||||
|
||||
//include::{srcdir}/chapters/counters.adoc[]
|
||||
|
||||
include::./common/chapters/vty_cpu_sched.adoc[]
|
||||
|
||||
include::./common/chapters/port_numbers.adoc[]
|
||||
|
||||
include::./common/chapters/bibliography.adoc[]
|
||||
|
||||
include::./common/chapters/glossary.adoc[]
|
||||
|
||||
include::./common/chapters/gfdl.adoc[]
|
38
doc/manuals/osmomgw-vty-reference.xml
Normal file
38
doc/manuals/osmomgw-vty-reference.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
ex:ts=2:sw=42sts=2:et
|
||||
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
-->
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
|
||||
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
|
||||
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
|
||||
<!ENTITY sections-vty SYSTEM "generated/docbook_vty.xml" >
|
||||
]>
|
||||
|
||||
<book>
|
||||
<info>
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>v1</revnumber>
|
||||
<date>12th December 2017</date>
|
||||
<authorinitials>pm</authorinitials>
|
||||
<revremark>Initial</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<title>OsmoMGW VTY Reference</title>
|
||||
|
||||
<copyright>
|
||||
<year>2017</year>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
|
||||
</para>
|
||||
</legalnotice>
|
||||
</info>
|
||||
|
||||
<!-- Main chapters-->
|
||||
&chapter-vty;
|
||||
</book>
|
||||
|
17
doc/manuals/regen_doc.sh
Executable file
17
doc/manuals/regen_doc.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
|
||||
OSMO_MGW_BRANCH=$COMMIT ./regen_doc.sh osmo-mgw 4243 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/mgw_vty_reference.xml"
|
2
doc/manuals/vty/mgw_vty_additions.xml
Normal file
2
doc/manuals/vty/mgw_vty_additions.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
||||
</vtydoc>
|
@@ -92,8 +92,8 @@ fi
|
||||
if test -n "$v"
|
||||
then
|
||||
: # use $v
|
||||
elif test -d ./.git \
|
||||
&& v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
elif
|
||||
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||
&& case $v in
|
||||
[0-9]*) ;;
|
||||
|
@@ -3,14 +3,17 @@ SUBDIRS = \
|
||||
$(NULL)
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
osmocom/legacy_mgcp/mgcp.h \
|
||||
osmocom/legacy_mgcp/mgcp_internal.h \
|
||||
osmocom/legacy_mgcp/osmux.h \
|
||||
osmocom/mgcp_client/mgcp_client.h \
|
||||
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_client_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_common.h \
|
||||
osmocom/mgcp_client/mgcp_client_pool.h \
|
||||
osmocom/mgcp/mgcp.h \
|
||||
osmocom/mgcp/mgcp_common.h \
|
||||
osmocom/mgcp/mgcp_internal.h \
|
||||
osmocom/mgcp/osmux.h \
|
||||
$(NULL)
|
||||
|
||||
# This gets copied during make from osmocom/mgcp/mgcp_common.h. Therefore it is not included in the source tree and we
|
||||
# don't need to distribute it (OS#4084).
|
||||
nobase_nodist_include_HEADERS = \
|
||||
osmocom/mgcp_client/mgcp_common.h \
|
||||
$(NULL)
|
||||
|
@@ -1,5 +1,4 @@
|
||||
SUBDIRS = \
|
||||
legacy_mgcp \
|
||||
mgcp_client \
|
||||
mgcp \
|
||||
$(NULL)
|
||||
|
@@ -1,4 +0,0 @@
|
||||
noinst_HEADERS = \
|
||||
mgcp_transcode.h \
|
||||
vty.h \
|
||||
$(NULL)
|
@@ -1,298 +0,0 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENBSC_MGCP_H
|
||||
#define OPENBSC_MGCP_H
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define RTP_PORT_DEFAULT 4000
|
||||
#define RTP_PORT_NET_DEFAULT 16000
|
||||
|
||||
/**
|
||||
* Calculate the RTP audio port for the given multiplex
|
||||
* and the direction. This allows a semi static endpoint
|
||||
* to port calculation removing the need for the BSC
|
||||
* and the MediaGateway to communicate.
|
||||
*
|
||||
* Port usage explained:
|
||||
* base + (multiplex * 2) + 0 == local port to wait for network packets
|
||||
* base + (multiplex * 2) + 1 == local port for rtcp
|
||||
*
|
||||
* The above port will receive packets from the BTS that need
|
||||
* to be patched and forwarded to the network.
|
||||
* The above port will receive packets from the network that
|
||||
* need to be patched and forwarded to the BTS.
|
||||
*
|
||||
* We assume to have a static BTS IP address so we can differentiate
|
||||
* network and BTS.
|
||||
*
|
||||
*/
|
||||
static inline int rtp_calculate_port(int multiplex, int base)
|
||||
{
|
||||
return base + (multiplex * 2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handling of MGCP Endpoints and the MGCP Config
|
||||
*/
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_config;
|
||||
struct mgcp_trunk_config;
|
||||
struct mgcp_rtp_end;
|
||||
|
||||
#define MGCP_ENDP_CRCX 1
|
||||
#define MGCP_ENDP_DLCX 2
|
||||
#define MGCP_ENDP_MDCX 3
|
||||
|
||||
/*
|
||||
* what to do with the msg?
|
||||
* - continue as usual?
|
||||
* - reject and send a failure code?
|
||||
* - defer? do not send anything
|
||||
*/
|
||||
#define MGCP_POLICY_CONT 4
|
||||
#define MGCP_POLICY_REJECT 5
|
||||
#define MGCP_POLICY_DEFER 6
|
||||
|
||||
typedef int (*mgcp_realloc)(struct mgcp_trunk_config *cfg, int endpoint);
|
||||
typedef int (*mgcp_change)(struct mgcp_trunk_config *cfg, int endpoint, int state);
|
||||
typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int state, const char *transactio_id);
|
||||
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
|
||||
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
||||
|
||||
/**
|
||||
* Return:
|
||||
* < 0 in case no audio was processed
|
||||
* >= 0 in case audio was processed. The remaining payload
|
||||
* length will be returned.
|
||||
*/
|
||||
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end);
|
||||
|
||||
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**subtype_name,
|
||||
const char**fmtp_extra);
|
||||
|
||||
#define PORT_ALLOC_STATIC 0
|
||||
#define PORT_ALLOC_DYNAMIC 1
|
||||
|
||||
/**
|
||||
* This holds information on how to allocate ports
|
||||
*/
|
||||
struct mgcp_port_range {
|
||||
int mode;
|
||||
|
||||
/* addr or NULL to fall-back to default */
|
||||
char *bind_addr;
|
||||
|
||||
/* pre-allocated from a base? */
|
||||
int base_port;
|
||||
|
||||
/* dynamically allocated */
|
||||
int range_start;
|
||||
int range_end;
|
||||
int last_port;
|
||||
};
|
||||
|
||||
#define MGCP_KEEPALIVE_ONCE (-1)
|
||||
|
||||
struct mgcp_trunk_config {
|
||||
struct llist_head entry;
|
||||
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
int trunk_nr;
|
||||
int trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
char *audio_name;
|
||||
int audio_payload;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
int audio_loop;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* timer */
|
||||
struct osmo_timer_list keepalive_timer;
|
||||
|
||||
unsigned int number_endpoints;
|
||||
struct mgcp_endpoint *endpoints;
|
||||
};
|
||||
|
||||
enum mgcp_role {
|
||||
MGCP_BSC = 0,
|
||||
MGCP_BSC_NAT,
|
||||
};
|
||||
|
||||
enum mgcp_connection_mode {
|
||||
MGCP_CONN_NONE = 0,
|
||||
MGCP_CONN_RECV_ONLY = 1,
|
||||
MGCP_CONN_SEND_ONLY = 2,
|
||||
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
|
||||
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
|
||||
};
|
||||
|
||||
struct mgcp_config {
|
||||
int source_port;
|
||||
char *local_ip;
|
||||
char *source_addr;
|
||||
char *bts_ip;
|
||||
char *call_agent_addr;
|
||||
|
||||
struct in_addr bts_in;
|
||||
|
||||
/* transcoder handling */
|
||||
char *transcoder_ip;
|
||||
struct in_addr transcoder_in;
|
||||
int transcoder_remote_base;
|
||||
|
||||
/* RTP processing */
|
||||
mgcp_processing rtp_processing_cb;
|
||||
mgcp_processing_setup setup_rtp_processing_cb;
|
||||
|
||||
mgcp_get_format get_net_downlink_format_cb;
|
||||
|
||||
struct osmo_wqueue gw_fd;
|
||||
|
||||
struct mgcp_port_range bts_ports;
|
||||
struct mgcp_port_range net_ports;
|
||||
struct mgcp_port_range transcoder_ports;
|
||||
int endp_dscp;
|
||||
|
||||
int bts_force_ptime;
|
||||
|
||||
mgcp_change change_cb;
|
||||
mgcp_policy policy_cb;
|
||||
mgcp_reset reset_cb;
|
||||
mgcp_realloc realloc_cb;
|
||||
mgcp_rqnt rqnt_cb;
|
||||
void *data;
|
||||
|
||||
uint32_t last_call_id;
|
||||
|
||||
/* trunk handling */
|
||||
struct mgcp_trunk_config trunk;
|
||||
struct llist_head trunks;
|
||||
|
||||
/* only used for start with a static configuration */
|
||||
int last_net_port;
|
||||
int last_bts_port;
|
||||
|
||||
enum mgcp_role role;
|
||||
|
||||
/* osmux translator: 0 means disabled, 1 means enabled */
|
||||
int osmux;
|
||||
/* addr to bind the server to */
|
||||
char *osmux_addr;
|
||||
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
|
||||
* the osmux socket is already initialized.
|
||||
*/
|
||||
int osmux_init;
|
||||
/* osmux batch factor: from 1 to 4 maximum */
|
||||
int osmux_batch;
|
||||
/* osmux batch size (in bytes) */
|
||||
int osmux_batch_size;
|
||||
/* osmux port */
|
||||
uint16_t osmux_port;
|
||||
/* Pad circuit with dummy messages until we see the first voice
|
||||
* message.
|
||||
*/
|
||||
uint16_t osmux_dummy;
|
||||
|
||||
/* Use a jitterbuffer on the bts-side receiver */
|
||||
bool bts_use_jibuf;
|
||||
/* Minimum and maximum buffer size for the jitter buffer, in ms */
|
||||
uint32_t bts_jitter_delay_min;
|
||||
uint32_t bts_jitter_delay_max;
|
||||
};
|
||||
|
||||
/* config management */
|
||||
struct mgcp_config *mgcp_config_alloc(void);
|
||||
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
|
||||
enum mgcp_role role);
|
||||
int mgcp_vty_init(void);
|
||||
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
|
||||
void mgcp_release_endp(struct mgcp_endpoint *endp);
|
||||
void mgcp_initialize_endp(struct mgcp_endpoint *endp);
|
||||
int mgcp_reset_transcoder(struct mgcp_config *cfg);
|
||||
void mgcp_format_stats(struct mgcp_endpoint *endp, char *stats, size_t size);
|
||||
int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter);
|
||||
|
||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
|
||||
|
||||
/*
|
||||
* format helper functions
|
||||
*/
|
||||
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
|
||||
|
||||
/* adc helper */
|
||||
static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
|
||||
{
|
||||
if (timeslot == 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Timeslot should not be 0\n");
|
||||
timeslot = 255;
|
||||
}
|
||||
|
||||
return timeslot + (32 * multiplex);
|
||||
}
|
||||
|
||||
static inline void mgcp_endpoint_to_timeslot(int endpoint, int *multiplex, int *timeslot)
|
||||
{
|
||||
*multiplex = endpoint / 32;
|
||||
*timeslot = endpoint % 32;
|
||||
}
|
||||
|
||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
|
||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
|
||||
|
||||
|
||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
|
||||
int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct sockaddr_in *addr, char *buf, int rc);
|
||||
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
|
||||
|
||||
#endif
|
@@ -1,351 +0,0 @@
|
||||
/* MGCP Private Data */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/netif/jibuf.h>
|
||||
|
||||
#define CI_UNUSED 0
|
||||
|
||||
enum mgcp_trunk_type {
|
||||
MGCP_TRUNK_VIRTUAL,
|
||||
MGCP_TRUNK_E1,
|
||||
};
|
||||
|
||||
struct mgcp_rtp_stream_state {
|
||||
uint32_t ssrc;
|
||||
uint16_t last_seq;
|
||||
uint32_t last_timestamp;
|
||||
uint32_t err_ts_counter;
|
||||
int32_t last_tsdelta;
|
||||
uint32_t last_arrival_time;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_state {
|
||||
int initialized;
|
||||
int patch_ssrc;
|
||||
|
||||
uint32_t orig_ssrc;
|
||||
|
||||
int seq_offset;
|
||||
|
||||
int32_t timestamp_offset;
|
||||
uint32_t packet_duration;
|
||||
|
||||
struct mgcp_rtp_stream_state in_stream;
|
||||
struct mgcp_rtp_stream_state out_stream;
|
||||
|
||||
/* jitter and packet loss calculation */
|
||||
int stats_initialized;
|
||||
uint16_t stats_base_seq;
|
||||
uint16_t stats_max_seq;
|
||||
uint32_t stats_ssrc;
|
||||
uint32_t stats_jitter;
|
||||
int32_t stats_transit;
|
||||
int stats_cycles;
|
||||
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_end {
|
||||
/* statistics */
|
||||
unsigned int packets;
|
||||
unsigned int octets;
|
||||
unsigned int dropped_packets;
|
||||
struct in_addr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
|
||||
/* audio codec information */
|
||||
struct mgcp_rtp_codec codec;
|
||||
struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */
|
||||
|
||||
/* per endpoint data */
|
||||
int frames_per_packet;
|
||||
uint32_t packet_duration_ms;
|
||||
char *fmtp_extra;
|
||||
int output_enabled;
|
||||
int force_output_ptime;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
void *rtp_process_data;
|
||||
|
||||
/*
|
||||
* Each end has a socket...
|
||||
*/
|
||||
struct osmo_fd rtp;
|
||||
struct osmo_fd rtcp;
|
||||
|
||||
int local_port;
|
||||
int local_alloc;
|
||||
};
|
||||
|
||||
enum {
|
||||
MGCP_TAP_BTS_IN,
|
||||
MGCP_TAP_BTS_OUT,
|
||||
MGCP_TAP_NET_IN,
|
||||
MGCP_TAP_NET_OUT,
|
||||
|
||||
/* last element */
|
||||
MGCP_TAP_COUNT
|
||||
};
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
int enabled;
|
||||
struct sockaddr_in forward;
|
||||
};
|
||||
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
|
||||
enum mgcp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_RTP_TRANSCODED,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
};
|
||||
|
||||
#include <osmocom/legacy_mgcp/osmux.h>
|
||||
|
||||
struct mgcp_endpoint {
|
||||
int allocated;
|
||||
uint32_t ci;
|
||||
char *callid;
|
||||
struct mgcp_lco local_options;
|
||||
int conn_mode;
|
||||
int orig_mode;
|
||||
|
||||
/* backpointer */
|
||||
struct mgcp_config *cfg;
|
||||
struct mgcp_trunk_config *tcfg;
|
||||
|
||||
/* port status for bts/net */
|
||||
struct mgcp_rtp_end bts_end;
|
||||
struct mgcp_rtp_end net_end;
|
||||
|
||||
/*
|
||||
* For transcoding we will send from the local_port
|
||||
* of trans_bts and it will arrive at trans_net from
|
||||
* where we will forward it to the network.
|
||||
*/
|
||||
struct mgcp_rtp_end trans_bts;
|
||||
struct mgcp_rtp_end trans_net;
|
||||
enum mgcp_type type;
|
||||
|
||||
/* sequence bits */
|
||||
struct mgcp_rtp_state net_state;
|
||||
struct mgcp_rtp_state bts_state;
|
||||
|
||||
/* fields for re-transmission */
|
||||
char *last_trans;
|
||||
char *last_response;
|
||||
|
||||
/* tap for the endpoint */
|
||||
struct mgcp_rtp_tap taps[MGCP_TAP_COUNT];
|
||||
|
||||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Allocated Osmux circuit ID for this endpoint */
|
||||
int allocated_cid;
|
||||
/* Used Osmux circuit ID for this endpoint */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
} osmux;
|
||||
|
||||
/* Jitter buffer */
|
||||
struct osmo_jibuf* bts_jb;
|
||||
/* Use a jitterbuffer on the bts-side receiver */
|
||||
bool bts_use_jibuf;
|
||||
/* Minimum and maximum buffer size for the jitter buffer, in ms */
|
||||
uint32_t bts_jitter_delay_min;
|
||||
uint32_t bts_jitter_delay_max;
|
||||
};
|
||||
|
||||
#define for_each_line(line, save) \
|
||||
for (line = strline_r(NULL, &save); line;\
|
||||
line = strline_r(NULL, &save))
|
||||
|
||||
static inline char *strline_r(char *str, char **saveptr)
|
||||
{
|
||||
char *result;
|
||||
|
||||
if (str)
|
||||
*saveptr = str;
|
||||
|
||||
result = *saveptr;
|
||||
|
||||
if (*saveptr != NULL) {
|
||||
*saveptr = strpbrk(*saveptr, "\r\n");
|
||||
|
||||
if (*saveptr != NULL) {
|
||||
char *eos = *saveptr;
|
||||
|
||||
if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
|
||||
(*saveptr)++;
|
||||
(*saveptr)++;
|
||||
if ((*saveptr)[0] == '\0')
|
||||
*saveptr = NULL;
|
||||
|
||||
*eos = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
|
||||
|
||||
/**
|
||||
* Internal structure while parsing a request
|
||||
*/
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_config *cfg;
|
||||
struct mgcp_endpoint *endp;
|
||||
char *trans;
|
||||
char *save;
|
||||
int found;
|
||||
};
|
||||
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp);
|
||||
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
|
||||
int mgcp_bind_trans_bts_rtp_port(struct mgcp_endpoint *enp, int rtp_port);
|
||||
int mgcp_bind_trans_net_rtp_port(struct mgcp_endpoint *enp, int rtp_port);
|
||||
int mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
|
||||
/* For transcoding we need to manage an in and an output that are connected */
|
||||
static inline int endp_back_channel(int endpoint)
|
||||
{
|
||||
return endpoint + 60;
|
||||
}
|
||||
|
||||
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index);
|
||||
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index);
|
||||
|
||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
|
||||
void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
|
||||
uint32_t *expected, int *loss);
|
||||
uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**subtype_name,
|
||||
const char**fmtp_extra);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
const uint32_t ssrc);
|
||||
|
||||
int mgcp_set_ip_tos(int fd, int tos);
|
||||
|
||||
enum {
|
||||
MGCP_DEST_NET = 0,
|
||||
MGCP_DEST_BTS,
|
||||
};
|
||||
|
||||
|
||||
#define MGCP_DUMMY_LOAD 0x23
|
||||
|
||||
|
||||
/**
|
||||
* SDP related information
|
||||
*/
|
||||
/* Assume audio frame length of 20ms */
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
|
||||
|
||||
#define PTYPE_UNDEFINED (-1)
|
||||
int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p);
|
||||
int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
|
||||
int payload_type, const char *audio_name);
|
||||
|
||||
|
||||
/**
|
||||
* Internal network related
|
||||
*/
|
||||
static inline const char *mgcp_net_src_addr(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (endp->cfg->net_ports.bind_addr)
|
||||
return endp->cfg->net_ports.bind_addr;
|
||||
return endp->cfg->source_addr;
|
||||
}
|
||||
|
||||
static inline const char *mgcp_bts_src_addr(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (endp->cfg->bts_ports.bind_addr)
|
||||
return endp->cfg->bts_ports.bind_addr;
|
||||
return endp->cfg->source_addr;
|
||||
}
|
||||
|
||||
int mgcp_msg_terminate_nul(struct msgb *msg);
|
||||
|
||||
/**
|
||||
* Internal jitter buffer related
|
||||
*/
|
||||
void mgcp_dejitter_udp_send(struct msgb *msg, void *data);
|
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* (C) 2014 by On-Waves
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENBSC_MGCP_TRANSCODE_H
|
||||
#define OPENBSC_MGCP_TRANSCODE_H
|
||||
|
||||
#include "bscconfig.h"
|
||||
|
||||
#include <gsm.h>
|
||||
#ifdef HAVE_BCG729
|
||||
#include <bcg729/decoder.h>
|
||||
#include <bcg729/encoder.h>
|
||||
#endif
|
||||
|
||||
enum audio_format {
|
||||
AF_INVALID,
|
||||
AF_S16,
|
||||
AF_L16,
|
||||
AF_GSM,
|
||||
AF_G729,
|
||||
AF_PCMA,
|
||||
AF_PCMU
|
||||
};
|
||||
|
||||
|
||||
struct mgcp_process_rtp_state {
|
||||
/* decoding */
|
||||
enum audio_format src_fmt;
|
||||
union {
|
||||
gsm gsm_handle;
|
||||
#ifdef HAVE_BCG729
|
||||
bcg729DecoderChannelContextStruct *g729_dec;
|
||||
#endif
|
||||
} src;
|
||||
size_t src_frame_size;
|
||||
size_t src_samples_per_frame;
|
||||
|
||||
/* processing */
|
||||
|
||||
/* encoding */
|
||||
enum audio_format dst_fmt;
|
||||
union {
|
||||
gsm gsm_handle;
|
||||
#ifdef HAVE_BCG729
|
||||
bcg729EncoderChannelContextStruct *g729_enc;
|
||||
#endif
|
||||
} dst;
|
||||
size_t dst_frame_size;
|
||||
size_t dst_samples_per_frame;
|
||||
int dst_packet_duration;
|
||||
|
||||
int is_running;
|
||||
uint16_t next_seq;
|
||||
uint32_t next_time;
|
||||
int16_t samples[10*160];
|
||||
size_t sample_cnt;
|
||||
size_t sample_offs;
|
||||
};
|
||||
|
||||
|
||||
int mgcp_transcoding_setup(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end);
|
||||
|
||||
void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**audio_name,
|
||||
const char**fmtp_extra);
|
||||
|
||||
int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst);
|
||||
#endif /* OPENBSC_MGCP_TRANSCODE_H */
|
@@ -1,41 +0,0 @@
|
||||
#ifndef _OPENBSC_OSMUX_H_
|
||||
#define _OPENBSC_OSMUX_H_
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
|
||||
#define OSMUX_PORT 1984
|
||||
|
||||
enum {
|
||||
OSMUX_ROLE_BSC = 0,
|
||||
OSMUX_ROLE_BSC_NAT,
|
||||
};
|
||||
|
||||
int osmux_init(int role, struct mgcp_config *cfg);
|
||||
int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port);
|
||||
void osmux_disable_endpoint(struct mgcp_endpoint *endp);
|
||||
void osmux_allocate_cid(struct mgcp_endpoint *endp);
|
||||
void osmux_release_cid(struct mgcp_endpoint *endp);
|
||||
|
||||
int osmux_xfrm_to_rtp(struct mgcp_endpoint *endp, int type, char *buf, int rc);
|
||||
int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp);
|
||||
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp);
|
||||
|
||||
int osmux_get_cid(void);
|
||||
void osmux_put_cid(uint8_t osmux_cid);
|
||||
int osmux_used_cid(void);
|
||||
|
||||
enum osmux_state {
|
||||
OSMUX_STATE_DISABLED = 0,
|
||||
OSMUX_STATE_NEGOTIATING,
|
||||
OSMUX_STATE_ACTIVATING,
|
||||
OSMUX_STATE_ENABLED,
|
||||
};
|
||||
|
||||
enum osmux_usage {
|
||||
OSMUX_USAGE_OFF = 0,
|
||||
OSMUX_USAGE_ON = 1,
|
||||
OSMUX_USAGE_ONLY = 2,
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
|
||||
enum mgcp_vty_node {
|
||||
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
TRUNK_NODE,
|
||||
};
|
@@ -6,5 +6,11 @@ noinst_HEADERS = \
|
||||
mgcp_endp.h \
|
||||
mgcp_sdp.h \
|
||||
mgcp_codec.h \
|
||||
mgcp_ctrl.h \
|
||||
mgcp_trunk.h \
|
||||
debug.h \
|
||||
mgcp_ratectr.h \
|
||||
mgcp_e1.h \
|
||||
mgcp_network.h \
|
||||
mgcp_protocol.h \
|
||||
$(NULL)
|
||||
|
@@ -29,6 +29,7 @@
|
||||
/* Debug Areas of the code */
|
||||
enum {
|
||||
DRTP,
|
||||
DE1,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
@@ -33,6 +34,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "mgcp_ratectr.h"
|
||||
|
||||
#define RTP_PORT_DEFAULT_RANGE_START 16002
|
||||
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
|
||||
@@ -42,7 +46,7 @@
|
||||
*/
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_config;
|
||||
struct mgcp_trunk_config;
|
||||
struct mgcp_trunk;
|
||||
struct mgcp_rtp_end;
|
||||
|
||||
#define MGCP_ENDP_CRCX 1
|
||||
@@ -59,10 +63,7 @@ struct mgcp_rtp_end;
|
||||
#define MGCP_POLICY_REJECT 5
|
||||
#define MGCP_POLICY_DEFER 6
|
||||
|
||||
typedef int (*mgcp_realloc)(struct mgcp_trunk_config *cfg, int endpoint);
|
||||
typedef int (*mgcp_change)(struct mgcp_trunk_config *cfg, int endpoint, int state);
|
||||
typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int state, const char *transactio_id);
|
||||
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
|
||||
typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
|
||||
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
||||
|
||||
/**
|
||||
@@ -74,23 +75,28 @@ typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
||||
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end);
|
||||
|
||||
struct mgcp_conn_rtp;
|
||||
|
||||
typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
struct mgcp_rtp_codec;
|
||||
|
||||
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**subtype_name,
|
||||
const char**fmtp_extra,
|
||||
const struct mgcp_rtp_codec **codec,
|
||||
const char **fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/**
|
||||
* This holds information on how to allocate ports
|
||||
*/
|
||||
struct mgcp_port_range {
|
||||
pthread_mutex_t lock;
|
||||
/* addr or NULL to fall-back to default */
|
||||
char *bind_addr;
|
||||
char bind_addr_v4[INET6_ADDRSTRLEN];
|
||||
char bind_addr_v6[INET6_ADDRSTRLEN];
|
||||
|
||||
/* dynamically allocated */
|
||||
int range_start;
|
||||
@@ -116,45 +122,6 @@ struct mgcp_port_range {
|
||||
#define MGCP_KEEPALIVE_ONCE (-1)
|
||||
#define MGCP_KEEPALIVE_NEVER 0
|
||||
|
||||
struct mgcp_trunk_config {
|
||||
struct llist_head entry;
|
||||
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
int trunk_nr;
|
||||
int trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
char *audio_name;
|
||||
int audio_payload;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
int audio_loop;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* timer */
|
||||
struct osmo_timer_list keepalive_timer;
|
||||
|
||||
/* When set, incoming RTP packets are not filtered
|
||||
* when ports and ip-address do not match (debug) */
|
||||
int rtp_accept_all;
|
||||
|
||||
unsigned int number_endpoints;
|
||||
int vty_number_endpoints;
|
||||
struct mgcp_endpoint *endpoints;
|
||||
};
|
||||
|
||||
enum mgcp_role {
|
||||
MGCP_BSC = 0,
|
||||
MGCP_BSC_NAT,
|
||||
@@ -162,9 +129,9 @@ enum mgcp_role {
|
||||
|
||||
struct mgcp_config {
|
||||
int source_port;
|
||||
char *local_ip;
|
||||
char *source_addr;
|
||||
char *call_agent_addr;
|
||||
char local_ip[INET6_ADDRSTRLEN];
|
||||
char source_addr[INET6_ADDRSTRLEN];
|
||||
char call_agent_addr[INET6_ADDRSTRLEN];
|
||||
|
||||
/* RTP processing */
|
||||
mgcp_processing rtp_processing_cb;
|
||||
@@ -176,20 +143,15 @@ struct mgcp_config {
|
||||
|
||||
struct mgcp_port_range net_ports;
|
||||
int endp_dscp;
|
||||
int endp_priority;
|
||||
|
||||
int force_ptime;
|
||||
|
||||
mgcp_change change_cb;
|
||||
mgcp_policy policy_cb;
|
||||
mgcp_reset reset_cb;
|
||||
mgcp_realloc realloc_cb;
|
||||
mgcp_rqnt rqnt_cb;
|
||||
void *data;
|
||||
|
||||
uint32_t last_call_id;
|
||||
|
||||
/* trunk handling */
|
||||
struct mgcp_trunk_config trunk;
|
||||
/* list holding the trunks */
|
||||
struct llist_head trunks;
|
||||
|
||||
enum mgcp_role role;
|
||||
@@ -197,7 +159,7 @@ struct mgcp_config {
|
||||
/* osmux translator: 0 means disabled, 1 means enabled */
|
||||
int osmux;
|
||||
/* addr to bind the server to */
|
||||
char *osmux_addr;
|
||||
char osmux_addr[INET6_ADDRSTRLEN];
|
||||
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
|
||||
* the osmux socket is already initialized.
|
||||
*/
|
||||
@@ -214,6 +176,16 @@ struct mgcp_config {
|
||||
uint16_t osmux_dummy;
|
||||
/* domain name of the media gateway */
|
||||
char domain[255+1];
|
||||
|
||||
/* time after which inactive connections (CIs) get closed */
|
||||
int conn_timeout;
|
||||
|
||||
/* osmocom CTRL interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
|
||||
/* global rate counters to measure the MGWs overall performance and
|
||||
* health */
|
||||
struct mgcp_ratectr_global ratectr;
|
||||
};
|
||||
|
||||
/* config management */
|
||||
@@ -221,8 +193,7 @@ struct mgcp_config *mgcp_config_alloc(void);
|
||||
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
|
||||
enum mgcp_role role);
|
||||
int mgcp_vty_init(void);
|
||||
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
|
||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
|
||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval);
|
||||
|
||||
/*
|
||||
* format helper functions
|
||||
@@ -230,9 +201,10 @@ void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
|
||||
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
|
||||
|
||||
|
||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
|
||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
|
||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
|
||||
|
||||
|
||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
|
||||
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
|
||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
|
||||
uint8_t prio);
|
||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
|
||||
|
@@ -1,6 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
|
||||
|
||||
#define PTYPE_UNDEFINED (-1)
|
||||
|
||||
struct mgcp_conn_rtp;
|
||||
|
||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
|
||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name);
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
|
||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
|
||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
|
||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
|
||||
const char *subtype_name, unsigned int match_nr);
|
||||
|
@@ -49,6 +49,21 @@ enum mgcp_connection_mode {
|
||||
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
|
||||
};
|
||||
|
||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
|
||||
#define MGCP_X_OSMO_OSMUX_HEADER "X-Osmux:"
|
||||
|
||||
/* Values should be bitwise-OR-able */
|
||||
enum mgcp_x_osmo_ign {
|
||||
MGCP_X_OSMO_IGN_NONE = 0,
|
||||
MGCP_X_OSMO_IGN_CALLID = 1,
|
||||
};
|
||||
|
||||
/* Codec parameters (communicated via SDP/fmtp) */
|
||||
struct mgcp_codec_param {
|
||||
bool amr_octet_aligned_present;
|
||||
bool amr_octet_aligned;
|
||||
};
|
||||
|
||||
/* Ensure that the msg->l2h is NUL terminated. */
|
||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
{
|
||||
@@ -71,9 +86,12 @@ static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
/* Maximum length of the comment field */
|
||||
#define MGCP_COMMENT_MAXLEN 256
|
||||
|
||||
/* String length of Connection Identifiers
|
||||
* (see also RFC3435 2.1.3.2 Names of Connections) */
|
||||
#define MGCP_CONN_ID_LENGTH 32+1
|
||||
/* Maximum allowed String length of Connection Identifiers as per spec
|
||||
* (see also RFC3435 2.1.3.2 Names of Connections), plus one for '\0'. */
|
||||
#define MGCP_CONN_ID_MAXLEN 32+1
|
||||
|
||||
/* Deprecated: old name of MGCP_CONN_ID_MAXLEN. */
|
||||
#define MGCP_CONN_ID_LENGTH MGCP_CONN_ID_MAXLEN
|
||||
|
||||
/* String length of Endpoint Identifiers.
|
||||
/ (see also RFC3435 section 3.2.1.3) */
|
||||
@@ -82,6 +100,10 @@ static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
/* A prefix to denote the virtual trunk (RTP on both ends) */
|
||||
#define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"
|
||||
|
||||
/* A prefix to denote the e1 trunk
|
||||
* (see also RFC3435 section E.2) */
|
||||
#define MGCP_ENDPOINT_PREFIX_E1_TRUNK "ds/e1-"
|
||||
|
||||
/* Maximal number of payload types / codecs that can be negotiated via SDP at
|
||||
* at once. */
|
||||
#define MGCP_MAX_CODECS 10
|
||||
|
@@ -23,10 +23,159 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_network.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
|
||||
LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
|
||||
(conn)->id, \
|
||||
## args)
|
||||
|
||||
#define LOG_CONN(conn, level, fmt, args...) \
|
||||
LOGP(DRTP, level, "(%s I:%s) " fmt, \
|
||||
(conn)->endp ? (conn)->endp->name : "none", (conn)->id, ## args)
|
||||
|
||||
#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
|
||||
LOG_CONN((conn_rtp)->conn, level, fmt, ## args)
|
||||
|
||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
|
||||
enum mgcp_conn_rtp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
};
|
||||
|
||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||
* contains a useful connection description (currently only RTP) */
|
||||
enum mgcp_conn_type {
|
||||
MGCP_CONN_TYPE_RTP,
|
||||
};
|
||||
|
||||
/* MGCP connection (RTP) */
|
||||
struct mgcp_conn_rtp {
|
||||
|
||||
/* Backpointer to conn struct */
|
||||
struct mgcp_conn *conn;
|
||||
|
||||
/* Specific connection type */
|
||||
enum mgcp_conn_rtp_type type;
|
||||
|
||||
/* Port status */
|
||||
struct mgcp_rtp_end end;
|
||||
|
||||
/* Sequence bits */
|
||||
struct mgcp_rtp_state state;
|
||||
|
||||
/* taps for the rtp connection; one per direction */
|
||||
struct mgcp_rtp_tap tap_in;
|
||||
struct mgcp_rtp_tap tap_out;
|
||||
|
||||
/* Osmux states (optional) */
|
||||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Is cid holding valid data? is it allocated from pool? */
|
||||
bool cid_allocated;
|
||||
/* Allocated Osmux circuit ID for this conn */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
} osmux;
|
||||
|
||||
struct rate_ctr_group *rate_ctr_group;
|
||||
};
|
||||
|
||||
/*! MGCP connection (untyped) */
|
||||
struct mgcp_conn {
|
||||
/*! list head */
|
||||
struct llist_head entry;
|
||||
|
||||
/*! Backpointer to the endpoint where the conn belongs to */
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/*! type of the connection (union) */
|
||||
enum mgcp_conn_type type;
|
||||
|
||||
/*! mode of the connection */
|
||||
enum mgcp_connection_mode mode;
|
||||
|
||||
/*! copy of the mode to restore the original setting (VTY) */
|
||||
enum mgcp_connection_mode mode_orig;
|
||||
|
||||
/*! connection id to identify the connection */
|
||||
char id[MGCP_CONN_ID_MAXLEN];
|
||||
|
||||
/*! human readable name (vty, logging) */
|
||||
char name[256];
|
||||
|
||||
/*! activity tracker (for cleaning up inactive connections) */
|
||||
struct osmo_timer_list watchdog;
|
||||
|
||||
/*! union with connection description */
|
||||
union {
|
||||
struct mgcp_conn_rtp rtp;
|
||||
} u;
|
||||
|
||||
/*! pointer to optional private data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* RTP connection related counters */
|
||||
enum {
|
||||
IN_STREAM_ERR_TSTMP_CTR,
|
||||
OUT_STREAM_ERR_TSTMP_CTR,
|
||||
RTP_PACKETS_RX_CTR,
|
||||
RTP_OCTETS_RX_CTR,
|
||||
RTP_PACKETS_TX_CTR,
|
||||
RTP_OCTETS_TX_CTR,
|
||||
RTP_DROPPED_PACKETS_CTR,
|
||||
RTP_NUM_CONNECTIONS,
|
||||
};
|
||||
|
||||
/* 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_rate_ctr_desc[] = {
|
||||
[IN_STREAM_ERR_TSTMP_CTR] = {"stream_err_tstmp:in", "Inbound rtp-stream timestamp errors."},
|
||||
[OUT_STREAM_ERR_TSTMP_CTR] = {"stream_err_tstmp:out", "Outbound rtp-stream timestamp errors."},
|
||||
[RTP_PACKETS_RX_CTR] = {"rtp:packets_rx", "Inbound rtp packets."},
|
||||
[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
|
||||
[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
|
||||
[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
|
||||
[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "dropped rtp packets."}
|
||||
};
|
||||
|
||||
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
|
||||
* Must be kept in sync with mgcp_conn_rate_ctr_desc above */
|
||||
static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
|
||||
[IN_STREAM_ERR_TSTMP_CTR] = {"all_rtp:err_tstmp_in", "Total inbound rtp-stream timestamp errors."},
|
||||
[OUT_STREAM_ERR_TSTMP_CTR] = {"all_rtp:err_tstmp_out", "Total outbound rtp-stream timestamp errors."},
|
||||
[RTP_PACKETS_RX_CTR] = {"all_rtp:packets_rx", "Total inbound rtp packets."},
|
||||
[RTP_OCTETS_RX_CTR] = {"all_rtp:octets_rx", "Total inbound rtp octets."},
|
||||
[RTP_PACKETS_TX_CTR] = {"all_rtp:packets_tx", "Total outbound rtp packets."},
|
||||
[RTP_OCTETS_TX_CTR] = {"all_rtp:octets_tx", "Total outbound rtp octets."},
|
||||
[RTP_DROPPED_PACKETS_CTR] = {"all_rtp:dropped", "Total dropped rtp packets."},
|
||||
|
||||
/* This last counter does not exist in per-connection stats, only here. */
|
||||
[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
|
||||
};
|
||||
|
||||
/* Was conn configured to handle Osmux? */
|
||||
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;
|
||||
}
|
||||
|
||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
||||
enum mgcp_conn_type type, char *name);
|
||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
|
||||
@@ -37,3 +186,5 @@ 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);
|
||||
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);
|
||||
|
24
include/osmocom/mgcp/mgcp_ctrl.h
Normal file
24
include/osmocom/mgcp/mgcp_ctrl.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* (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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
|
||||
const char *bind_addr, uint16_t port);
|
||||
|
27
include/osmocom/mgcp/mgcp_e1.h
Normal file
27
include/osmocom/mgcp/mgcp_e1.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
/* A 64k timeslot on an E1 line can be subdevied into the following
|
||||
* subslot combinations:
|
||||
*
|
||||
* subslot: offset:
|
||||
* [ ][ ][ 16k ][8k_subslot] 0
|
||||
* [ ][ 32k ][_subslot__][8k_subslot] 1
|
||||
* [ ][ subslot ][ 16k ][8k_subslot] 2
|
||||
* [ 64k ][__________][_subslot__][8k_subslot] 3
|
||||
* [ timeslot ][ ][ 16k ][8k_subslot] 4
|
||||
* [ ][ 32K ][_subslot__][8k_subslot] 5
|
||||
* [ ][ subslot ][ 16k ][8k_subslot] 6
|
||||
* [ ][ ][ subslot ][8k_subslot] 7
|
||||
*
|
||||
* Since overlapping assignment of subslots is not possible there is a limited
|
||||
* set of subslot assignments possible. The e1_rates array lists the possible
|
||||
* assignments as depicted above. Also each subslot assignment comes along with
|
||||
* a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit
|
||||
* offsets. */
|
||||
static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
|
||||
static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
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_release(struct mgcp_endpoint *endp);
|
||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
|
@@ -23,15 +23,36 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct sockaddr_in;
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/i460_mux.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
|
||||
struct sockaddr;
|
||||
struct mgcp_conn;
|
||||
struct mgcp_conn_rtp;
|
||||
struct mgcp_endpoint;
|
||||
|
||||
/* Callback type for RTP dispatcher functions
|
||||
(e.g mgcp_dispatch_rtp_bridge_cb, see below) */
|
||||
typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
|
||||
char *buf, unsigned int buf_size,
|
||||
struct mgcp_conn *conn);
|
||||
/* Number of E1 subslots (different variants, not all useable at the same time) */
|
||||
#define MGCP_ENDP_E1_SUBSLOTS 15
|
||||
|
||||
#define LOGPENDP(endp, cat, level, fmt, args...) \
|
||||
LOGP(cat, level, "endpoint:%s " fmt, \
|
||||
endp ? endp->name : "none", \
|
||||
## args)
|
||||
|
||||
struct osmo_rtp_msg_ctx {
|
||||
int proto;
|
||||
struct mgcp_conn_rtp *conn_src;
|
||||
struct osmo_sockaddr *from_addr;
|
||||
};
|
||||
|
||||
#define OSMO_RTP_MSG_CTX(MSGB) ((struct osmo_rtp_msg_ctx*)(MSGB)->cb)
|
||||
|
||||
osmo_static_assert(sizeof(((struct msgb*)0)->cb) >= sizeof(struct osmo_rtp_msg_ctx), osmo_rtp_msg_ctx_fits_in_msgb_cb);
|
||||
|
||||
/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).
|
||||
* The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */
|
||||
typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
|
||||
|
||||
/* Callback type for endpoint specific cleanup actions. This function
|
||||
* is automatically executed when a connection is freed (see mgcp_conn_free()
|
||||
@@ -42,19 +63,20 @@ typedef void (*mgcp_cleanup_cp) (struct mgcp_endpoint *endp,
|
||||
|
||||
/*! MGCP endpoint properties */
|
||||
struct mgcp_endpoint_type {
|
||||
/*!< maximum number of connections */
|
||||
/*! maximum number of connections */
|
||||
int max_conns;
|
||||
|
||||
/*!< callback that defines how to dispatch incoming RTP data */
|
||||
/*! callback that defines how to dispatch incoming RTP data */
|
||||
mgcp_dispatch_rtp_cb dispatch_rtp_cb;
|
||||
|
||||
/*!< callback that implements endpoint specific cleanup actions */
|
||||
/*! callback that implements endpoint specific cleanup actions */
|
||||
mgcp_cleanup_cp cleanup_cb;
|
||||
};
|
||||
|
||||
/*! MGCP endpoint typeset */
|
||||
struct mgcp_endpoint_typeset {
|
||||
struct mgcp_endpoint_type rtp;
|
||||
struct mgcp_endpoint_type e1;
|
||||
};
|
||||
|
||||
/*! static MGCP endpoint typeset (pre-initalized, read-only) */
|
||||
@@ -63,37 +85,58 @@ extern const struct mgcp_endpoint_typeset ep_typeset;
|
||||
/*! MGCP endpoint model */
|
||||
struct mgcp_endpoint {
|
||||
|
||||
/*!< Call identifier string (as supplied by the call agant) */
|
||||
/*! Unique endpoint name, used for addressing via MGCP */
|
||||
char *name;
|
||||
|
||||
/*! Call identifier string (as supplied by the call agant) */
|
||||
char *callid;
|
||||
|
||||
/*!< Local connection options (see mgcp_internal.h) */
|
||||
/*! Local connection options (see mgcp_internal.h) */
|
||||
struct mgcp_lco local_options;
|
||||
|
||||
/*!< List with connections active on this endpoint */
|
||||
/*! List of struct mgcp_conn, of the connections active on this endpoint */
|
||||
struct llist_head conns;
|
||||
|
||||
/*!< Backpointer to the MGW configuration */
|
||||
struct mgcp_config *cfg;
|
||||
/*! Backpointer to the trunk this endpoint belongs to */
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
/*!< Backpointer to the Trunk specific configuration */
|
||||
struct mgcp_trunk_config *tcfg;
|
||||
|
||||
/*!< Endpoint properties (see above) */
|
||||
/*! Endpoint properties (see above) */
|
||||
const struct mgcp_endpoint_type *type;
|
||||
|
||||
/*!< Last MGCP transmission (in case re-transmission is required) */
|
||||
/*! Last MGCP transmission (in case re-transmission is required) */
|
||||
char *last_trans;
|
||||
|
||||
/*!< Last MGCP response (in case re-transmission is required) */
|
||||
/*! Last MGCP response (in case re-transmission is required) */
|
||||
char *last_response;
|
||||
|
||||
/*!< Memorize if this endpoint was choosen by the MGW (wildcarded, true)
|
||||
* or if the user has choosen the particular endpoint explicitly. */
|
||||
bool wildcarded_req;
|
||||
/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
|
||||
uint32_t x_osmo_ign;
|
||||
|
||||
/* E1 specific */
|
||||
struct {
|
||||
struct osmo_i460_schan_desc scd;
|
||||
struct osmo_i460_subchan *schan;
|
||||
struct osmo_fsm_inst *trau_sync_fi;
|
||||
struct osmo_trau2rtp_state *trau_rtp_st;
|
||||
uint8_t last_amr_ft;
|
||||
struct mgcp_rtp_codec *last_codec;
|
||||
} e1;
|
||||
|
||||
};
|
||||
|
||||
/*! Extract endpoint number for a given endpoint */
|
||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
|
||||
|
||||
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);
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
|
||||
bool mgcp_endp_is_wildcarded(const char *epname);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
||||
struct mgcp_config *cfg);
|
||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
|
||||
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_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);
|
||||
|
@@ -1,341 +0,0 @@
|
||||
/* MGCP Private Data */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/counter.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
#define CI_UNUSED 0
|
||||
|
||||
/* FIXME: This this is only needed to compile the currently
|
||||
* broken OSMUX support. Remove when fixed */
|
||||
#define CONN_ID_BTS "0"
|
||||
#define CONN_ID_NET "1"
|
||||
|
||||
enum mgcp_trunk_type {
|
||||
MGCP_TRUNK_VIRTUAL,
|
||||
MGCP_TRUNK_E1,
|
||||
};
|
||||
|
||||
struct mgcp_rtp_stream_state {
|
||||
uint32_t ssrc;
|
||||
uint16_t last_seq;
|
||||
uint32_t last_timestamp;
|
||||
struct rate_ctr *err_ts_ctr;
|
||||
int32_t last_tsdelta;
|
||||
uint32_t last_arrival_time;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_state {
|
||||
/* has this state structure been initialized? */
|
||||
int initialized;
|
||||
|
||||
struct {
|
||||
/* are we patching the SSRC value? */
|
||||
int patch_ssrc;
|
||||
/* original SSRC (to which we shall patch any different SSRC) */
|
||||
uint32_t orig_ssrc;
|
||||
/* offset to apply on the sequence number */
|
||||
int seq_offset;
|
||||
/* offset to apply on the timestamp number */
|
||||
int32_t timestamp_offset;
|
||||
} patch;
|
||||
|
||||
/* duration of a packet (FIXME: in which unit?) */
|
||||
uint32_t packet_duration;
|
||||
|
||||
struct mgcp_rtp_stream_state in_stream;
|
||||
struct mgcp_rtp_stream_state out_stream;
|
||||
|
||||
/* jitter and packet loss calculation */
|
||||
struct {
|
||||
int initialized;
|
||||
uint16_t base_seq;
|
||||
uint16_t max_seq;
|
||||
uint32_t ssrc;
|
||||
uint32_t jitter;
|
||||
int32_t transit;
|
||||
int cycles;
|
||||
} stats;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
||||
struct mgcp_rtp_end {
|
||||
/* statistics */
|
||||
struct {
|
||||
unsigned int packets_rx;
|
||||
unsigned int octets_rx;
|
||||
unsigned int packets_tx;
|
||||
unsigned int octets_tx;
|
||||
unsigned int dropped_packets;
|
||||
} stats;
|
||||
|
||||
/* local IP address of the RTP socket */
|
||||
struct in_addr 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;
|
||||
/* FIXME: not used anymore, used to be [external] transcoding related */
|
||||
void *rtp_process_data;
|
||||
|
||||
/* Each end has a separate socket for RTP and RTCP */
|
||||
struct osmo_fd rtp;
|
||||
struct osmo_fd rtcp;
|
||||
|
||||
/* local UDP port number of the RTP socket; RTCP is +1 */
|
||||
int local_port;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
/* is this tap active (1) or not (0) */
|
||||
int enabled;
|
||||
/* IP/port to which we're forwarding the tapped data */
|
||||
struct sockaddr_in forward;
|
||||
};
|
||||
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
|
||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
|
||||
enum mgcp_conn_rtp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
};
|
||||
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
struct mgcp_conn;
|
||||
|
||||
/* MGCP connection (RTP) */
|
||||
struct mgcp_conn_rtp {
|
||||
|
||||
/* Backpointer to conn struct */
|
||||
struct mgcp_conn *conn;
|
||||
|
||||
/* Specific connection type */
|
||||
enum mgcp_conn_rtp_type type;
|
||||
|
||||
/* Port status */
|
||||
struct mgcp_rtp_end end;
|
||||
|
||||
/* Sequence bits */
|
||||
struct mgcp_rtp_state state;
|
||||
|
||||
/* taps for the rtp connection; one per direction */
|
||||
struct mgcp_rtp_tap tap_in;
|
||||
struct mgcp_rtp_tap tap_out;
|
||||
|
||||
/* Osmux states (optional) */
|
||||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Allocated Osmux circuit ID for this endpoint */
|
||||
int allocated_cid;
|
||||
/* Used Osmux circuit ID for this endpoint */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
} osmux;
|
||||
|
||||
struct rate_ctr_group *rate_ctr_group;
|
||||
};
|
||||
|
||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||
* contains a useful connection description (currently only RTP) */
|
||||
enum mgcp_conn_type {
|
||||
MGCP_CONN_TYPE_RTP,
|
||||
};
|
||||
|
||||
/*! MGCP connection (untyped) */
|
||||
struct mgcp_conn {
|
||||
/*!< list head */
|
||||
struct llist_head entry;
|
||||
|
||||
/*!< Backpointer to the endpoint where the conn belongs to */
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/*!< type of the connection (union) */
|
||||
enum mgcp_conn_type type;
|
||||
|
||||
/*!< mode of the connection */
|
||||
enum mgcp_connection_mode mode;
|
||||
|
||||
/*!< copy of the mode to restore the original setting (VTY) */
|
||||
enum mgcp_connection_mode mode_orig;
|
||||
|
||||
/*!< connection id to identify the connection */
|
||||
char id[MGCP_CONN_ID_LENGTH];
|
||||
|
||||
/*!< human readable name (vty, logging) */
|
||||
char name[256];
|
||||
|
||||
/*!< union with connection description */
|
||||
union {
|
||||
struct mgcp_conn_rtp rtp;
|
||||
} u;
|
||||
|
||||
/*!< pointer to optional private data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
|
||||
struct mgcp_endpoint_type;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal structure while parsing a request
|
||||
*/
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_config *cfg;
|
||||
struct mgcp_endpoint *endp;
|
||||
char *trans;
|
||||
char *save;
|
||||
};
|
||||
|
||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
|
||||
char *buf, int rc, struct mgcp_conn_rtp *conn_src,
|
||||
struct mgcp_conn_rtp *conn_dst);
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
|
||||
unsigned int buf_size, struct mgcp_conn *conn);
|
||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
|
||||
/* For transcoding we need to manage an in and an output that are connected */
|
||||
static inline int endp_back_channel(int endpoint)
|
||||
{
|
||||
return endpoint + 60;
|
||||
}
|
||||
|
||||
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index);
|
||||
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index);
|
||||
|
||||
char *get_lco_identifier(const char *options);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**audio_name,
|
||||
const char**fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
const uint32_t ssrc);
|
||||
|
||||
int mgcp_set_ip_tos(int fd, int tos);
|
||||
|
||||
enum {
|
||||
MGCP_DEST_NET = 0,
|
||||
MGCP_DEST_BTS,
|
||||
};
|
||||
|
||||
|
||||
#define MGCP_DUMMY_LOAD 0x23
|
||||
|
||||
|
||||
/**
|
||||
* SDP related information
|
||||
*/
|
||||
/* Assume audio frame length of 20ms */
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
|
||||
|
||||
#define PTYPE_UNDEFINED (-1)
|
||||
|
||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
@@ -25,10 +25,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mgcp_conn;
|
||||
struct mgcp_parse_data;
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_trunk;
|
||||
|
||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
|
||||
|
||||
@@ -39,7 +41,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
|
||||
|
||||
int mgcp_parse_osmux_cid(const char *line);
|
||||
|
||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
|
||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
|
||||
|
||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
|
||||
|
||||
|
179
include/osmocom/mgcp/mgcp_network.h
Normal file
179
include/osmocom/mgcp/mgcp_network.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
|
||||
/* The following constant defines an RTP dummy payload that is used for
|
||||
* "UDP Hole Punching" (NAT) */
|
||||
static const char rtp_dummy_payload[] = { 0x23 };
|
||||
|
||||
/* Check if the data in a given message buffer matches the rtp dummy payload
|
||||
* defined above */
|
||||
#define mgcp_is_rtp_dummy_payload(msg) \
|
||||
(msgb_length(msg) == sizeof(rtp_dummy_payload) && \
|
||||
memcmp(msgb_data(msg), rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0)
|
||||
|
||||
#define RTP_BUF_SIZE 4096
|
||||
|
||||
struct mgcp_rtp_stream_state {
|
||||
uint32_t ssrc;
|
||||
uint16_t last_seq;
|
||||
uint32_t last_timestamp;
|
||||
struct rate_ctr *err_ts_ctr;
|
||||
int32_t last_tsdelta;
|
||||
uint32_t last_arrival_time;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_state {
|
||||
/* has this state structure been initialized? */
|
||||
int initialized;
|
||||
|
||||
struct {
|
||||
/* are we patching the SSRC value? */
|
||||
bool patch_ssrc;
|
||||
/* original SSRC (to which we shall patch any different SSRC) */
|
||||
uint32_t orig_ssrc;
|
||||
/* offset to apply on the sequence number */
|
||||
int seq_offset;
|
||||
/* offset to apply on the timestamp number */
|
||||
int32_t timestamp_offset;
|
||||
} patch;
|
||||
|
||||
/* duration of a packet (FIXME: in which unit?) */
|
||||
uint32_t packet_duration;
|
||||
|
||||
/* Note: These states are not continuously updated, they serve as an
|
||||
* information source to patch certain values in the RTP header. Do
|
||||
* not use this state if constantly updated data about the RTP stream
|
||||
* is needed. (see also mgcp_patch_and_count() */
|
||||
struct mgcp_rtp_stream_state in_stream;
|
||||
struct mgcp_rtp_stream_state out_stream;
|
||||
|
||||
/* jitter and packet loss calculation */
|
||||
struct {
|
||||
int initialized;
|
||||
uint16_t base_seq;
|
||||
uint16_t max_seq;
|
||||
uint32_t ssrc;
|
||||
uint32_t jitter;
|
||||
int32_t transit;
|
||||
int cycles;
|
||||
} stats;
|
||||
|
||||
/* Alternative values for RTP tx, in case no sufficient header
|
||||
* information is available so the header needs to be generated
|
||||
* locally (when just forwarding packets, the header of incoming
|
||||
* data is just re-used) */
|
||||
uint16_t alt_rtp_tx_sequence;
|
||||
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[64];
|
||||
char subtype_name[64];
|
||||
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
||||
struct mgcp_rtp_end {
|
||||
/* remote IP address of the RTP socket */
|
||||
struct osmo_sockaddr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int 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];
|
||||
};
|
||||
|
||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
/* is this tap active (1) or not (0) */
|
||||
int enabled;
|
||||
/* IP/port to which we're forwarding the tapped data */
|
||||
struct osmo_sockaddr forward;
|
||||
};
|
||||
|
||||
struct mgcp_conn;
|
||||
|
||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
|
||||
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
|
||||
struct mgcp_conn_rtp *conn_dst);
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
|
||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
|
||||
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,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_state *state,
|
||||
struct mgcp_rtp_end *rtp_end,
|
||||
struct osmo_sockaddr *addr, struct msgb *msg);
|
||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_codec **codec,
|
||||
const char **fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
const uint32_t ssrc, const bool marker_bit);
|
30
include/osmocom/mgcp/mgcp_protocol.h
Normal file
30
include/osmocom/mgcp/mgcp_protocol.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
/* Internal structure while parsing a request */
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_config *cfg;
|
||||
char *epname;
|
||||
char *trans;
|
||||
char *save;
|
||||
};
|
||||
|
||||
/* Local connection options */
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* 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);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
|
||||
struct mgcp_rtp_end;
|
||||
struct mgcp_endpoint;
|
||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
|
||||
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_end *rtp);
|
107
include/osmocom/mgcp/mgcp_ratectr.h
Normal file
107
include/osmocom/mgcp/mgcp_ratectr.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
|
||||
/* Global MCGP general rate counters */
|
||||
enum {
|
||||
MGCP_GENERAL_RX_MSGS_TOTAL,
|
||||
MGCP_GENERAL_RX_MSGS_RETRANSMITTED,
|
||||
MGCP_GENERAL_RX_MSGS_HANDLED,
|
||||
MGCP_GENERAL_RX_MSGS_UNHANDLED,
|
||||
MGCP_GENERAL_RX_FAIL_MSG_PARSE,
|
||||
MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP CRCX related rate counters */
|
||||
enum {
|
||||
MGCP_CRCX_SUCCESS,
|
||||
MGCP_CRCX_FAIL_BAD_ACTION,
|
||||
MGCP_CRCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_CRCX_FAIL_MISSING_CALLID,
|
||||
MGCP_CRCX_FAIL_INVALID_MODE,
|
||||
MGCP_CRCX_FAIL_LIMIT_EXCEEDED,
|
||||
MGCP_CRCX_FAIL_UNKNOWN_CALLID,
|
||||
MGCP_CRCX_FAIL_ALLOC_CONN,
|
||||
MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_CRCX_FAIL_START_RTP,
|
||||
MGCP_CRCX_FAIL_NO_OSMUX,
|
||||
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
|
||||
MGCP_CRCX_FAIL_BIND_PORT,
|
||||
MGCP_CRCX_FAIL_AVAIL,
|
||||
MGCP_CRCX_FAIL_CLAIM,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP MDCX related rate counters */
|
||||
enum {
|
||||
MGCP_MDCX_SUCCESS,
|
||||
MGCP_MDCX_FAIL_WILDCARD,
|
||||
MGCP_MDCX_FAIL_NO_CONN,
|
||||
MGCP_MDCX_FAIL_INVALID_CALLID,
|
||||
MGCP_MDCX_FAIL_INVALID_CONNID,
|
||||
MGCP_MDCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_MDCX_FAIL_NO_CONNID,
|
||||
MGCP_MDCX_FAIL_CONN_NOT_FOUND,
|
||||
MGCP_MDCX_FAIL_INVALID_MODE,
|
||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_MDCX_FAIL_START_RTP,
|
||||
MGCP_MDCX_FAIL_AVAIL,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP DLCX related rate counters */
|
||||
enum {
|
||||
MGCP_DLCX_SUCCESS,
|
||||
MGCP_DLCX_FAIL_NO_CONN,
|
||||
MGCP_DLCX_FAIL_INVALID_CALLID,
|
||||
MGCP_DLCX_FAIL_INVALID_CONNID,
|
||||
MGCP_DLCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_DLCX_FAIL_AVAIL,
|
||||
};
|
||||
|
||||
/* Trunk-global E1 related counters */
|
||||
enum {
|
||||
E1_I460_TRAU_RX_FAIL_CTR,
|
||||
E1_I460_TRAU_TX_FAIL_CTR,
|
||||
E1_I460_TRAU_MUX_EMPTY_CTR,
|
||||
};
|
||||
|
||||
/* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */
|
||||
|
||||
struct mgcp_ratectr_global {
|
||||
/* Rate counter group which contains stats for generic MGCP events. */
|
||||
struct rate_ctr_group *mgcp_general_ctr_group;
|
||||
};
|
||||
|
||||
struct mgcp_ratectr_trunk {
|
||||
/* Rate counter group which contains stats for processed CRCX commands. */
|
||||
struct rate_ctr_group *mgcp_crcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed MDCX commands. */
|
||||
struct rate_ctr_group *mgcp_mdcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed DLCX commands. */
|
||||
struct rate_ctr_group *mgcp_dlcx_ctr_group;
|
||||
/* Rate counter group which aggregates stats of individual RTP connections. */
|
||||
struct rate_ctr_group *all_rtp_conn_stats;
|
||||
/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
|
||||
struct rate_ctr_group *e1_stats;
|
||||
};
|
||||
|
||||
struct mgcp_config;
|
||||
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);
|
@@ -24,14 +24,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn);
|
||||
|
||||
/* Exposed for test purposes only, do not use actively */
|
||||
void calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
|
||||
uint32_t *expected, int *loss);
|
||||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss);
|
||||
|
||||
/* Exposed for test purposes only, do not use actively */
|
||||
uint32_t calc_jitter(struct mgcp_rtp_state *);
|
||||
|
88
include/osmocom/mgcp/mgcp_trunk.h
Normal file
88
include/osmocom/mgcp/mgcp_trunk.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsm/i460_mux.h>
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/mgcp/mgcp_ratectr.h>
|
||||
|
||||
|
||||
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
|
||||
LOGP(cat, level, "trunk:%u " fmt, \
|
||||
trunk ? trunk->trunk_nr : 0, \
|
||||
## args)
|
||||
|
||||
enum mgcp_trunk_type {
|
||||
MGCP_TRUNK_VIRTUAL,
|
||||
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 llist_head entry;
|
||||
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
unsigned int trunk_nr;
|
||||
enum mgcp_trunk_type trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
bool rfc5993_hr_convert;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* timer */
|
||||
struct osmo_timer_list keepalive_timer;
|
||||
|
||||
/* When set, incoming RTP packets are not filtered
|
||||
* when ports and ip-address do not match (debug) */
|
||||
int rtp_accept_all;
|
||||
|
||||
unsigned int number_endpoints;
|
||||
struct mgcp_endpoint **endpoints;
|
||||
|
||||
/* rate counters and stat items to measure the trunks overall performance and health */
|
||||
struct mgcp_ratectr_trunk ratectr;
|
||||
struct mgcp_stat_trunk stats;
|
||||
|
||||
union {
|
||||
/* Virtual trunk specific */
|
||||
struct {
|
||||
unsigned int vty_number_endpoints;
|
||||
} v;
|
||||
/* E1 specific */
|
||||
struct {
|
||||
unsigned int vty_line_nr;
|
||||
bool ts_in_use[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
|
||||
* alignment and therefore only NUM_E1_TS-1 timeslots
|
||||
* are available for traffic. */
|
||||
} e1;
|
||||
};
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* trunks may be assigned with arbritrary id numbers */
|
||||
#define MGCP_VIRT_TRUNK_ID 0
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
struct mgcp_conn_rtp;
|
||||
@@ -13,21 +14,23 @@ enum {
|
||||
|
||||
int osmux_init(int role, struct mgcp_config *cfg);
|
||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
struct in_addr *addr, uint16_t port);
|
||||
void osmux_disable_conn(struct mgcp_conn_rtp *conn);
|
||||
void osmux_allocate_cid(struct mgcp_conn_rtp *conn);
|
||||
void osmux_release_cid(struct mgcp_conn_rtp *conn);
|
||||
struct osmo_sockaddr *addr, uint16_t port);
|
||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
|
||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
|
||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
|
||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int osmux_get_cid(void);
|
||||
void osmux_put_cid(uint8_t osmux_cid);
|
||||
int osmux_used_cid(void);
|
||||
|
||||
void osmux_cid_pool_get(uint8_t osmux_cid);
|
||||
int osmux_cid_pool_get_next(void);
|
||||
void osmux_cid_pool_put(uint8_t osmux_cid);
|
||||
bool osmux_cid_pool_allocated(uint8_t osmux_cid);
|
||||
int osmux_cid_pool_count_used(void);
|
||||
|
||||
enum osmux_state {
|
||||
OSMUX_STATE_DISABLED = 0,
|
||||
OSMUX_STATE_NEGOTIATING,
|
||||
OSMUX_STATE_ACTIVATING,
|
||||
OSMUX_STATE_ENABLED,
|
||||
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_ENABLED, /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
|
||||
};
|
||||
|
||||
enum osmux_usage {
|
||||
@@ -35,4 +38,3 @@ enum osmux_usage {
|
||||
OSMUX_USAGE_ON = 1,
|
||||
OSMUX_USAGE_ONLY = 2,
|
||||
};
|
||||
|
||||
|
@@ -6,3 +6,7 @@ enum mgcp_vty_node {
|
||||
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
TRUNK_NODE,
|
||||
};
|
||||
|
||||
enum mgw_vty_cmd_attr {
|
||||
MGW_CMD_ATTR_NEWCONN = 0,
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@ BUILT_SOURCES = \
|
||||
|
||||
noinst_HEADERS = \
|
||||
mgcp_client_internal.h \
|
||||
mgcp_client_pool_internal.h \
|
||||
$(NULL)
|
||||
|
||||
mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
|
||||
|
@@ -5,11 +5,14 @@
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_common.h>
|
||||
|
||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
|
||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
|
||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
|
||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
|
||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
|
||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
|
||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
|
||||
|
||||
#define MGCP_CLIENT_MGW_STR "Configure MGCP connection to Media Gateway\n"
|
||||
|
||||
struct msgb;
|
||||
struct vty;
|
||||
struct mgcp_client;
|
||||
@@ -19,9 +22,19 @@ struct mgcp_client_conf {
|
||||
int local_port;
|
||||
const char *remote_addr;
|
||||
int remote_port;
|
||||
uint16_t first_endpoint;
|
||||
uint16_t last_endpoint;
|
||||
uint16_t bts_base;
|
||||
|
||||
/* 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'. */
|
||||
char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
|
||||
|
||||
/* The user may configure certain endpoint names that are reset via DLCX
|
||||
* on startup. Usually this will be one wildcarded endpoint e.g.
|
||||
* 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.
|
||||
* 'ds/e1-0/s-3/su16-4' */
|
||||
struct llist_head reset_epnames;
|
||||
|
||||
/* human readable name / description */
|
||||
char *description;
|
||||
};
|
||||
|
||||
typedef unsigned int mgcp_trans_id_t;
|
||||
@@ -33,7 +46,7 @@ enum mgcp_codecs {
|
||||
CODEC_PCMA_8000_1 = 8,
|
||||
CODEC_G729_8000_1 = 18,
|
||||
CODEC_GSMEFR_8000_1 = 110,
|
||||
CODEC_GSMHR_8000_1 = 111,
|
||||
CODEC_GSMHR_8000_1 = 111,
|
||||
CODEC_AMR_8000_1 = 112,
|
||||
CODEC_AMRWB_16000_1 = 113,
|
||||
};
|
||||
@@ -43,13 +56,17 @@ enum mgcp_codecs {
|
||||
* this is an internal assumption that is made to avoid lookup tables.
|
||||
* The API-User should not rely on this coincidence! */
|
||||
|
||||
extern const struct value_string osmo_mgcpc_codec_names[];
|
||||
static inline const char *osmo_mgcpc_codec_name(enum mgcp_codecs val)
|
||||
{ return get_value_string(osmo_mgcpc_codec_names, val); }
|
||||
|
||||
/*! Structure to build a payload type map to allow the defiition custom payload
|
||||
* types. */
|
||||
struct ptmap {
|
||||
/*!< codec for which a payload type number should be defined */
|
||||
/*! codec for which a payload type number should be defined */
|
||||
enum mgcp_codecs codec;
|
||||
|
||||
/*!< payload type number (96-127) */
|
||||
/*! payload type number (96-127) */
|
||||
unsigned int pt;
|
||||
};
|
||||
|
||||
@@ -57,20 +74,22 @@ struct mgcp_response_head {
|
||||
int response_code;
|
||||
mgcp_trans_id_t trans_id;
|
||||
char comment[MGCP_COMMENT_MAXLEN];
|
||||
char conn_id[MGCP_CONN_ID_LENGTH];
|
||||
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[INET_ADDRSTRLEN];
|
||||
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;
|
||||
unsigned int ptmap_len;
|
||||
};
|
||||
|
||||
enum mgcp_verb {
|
||||
@@ -87,6 +106,8 @@ enum mgcp_verb {
|
||||
#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;
|
||||
@@ -103,6 +124,11 @@ struct mgcp_msg {
|
||||
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);
|
||||
@@ -113,13 +139,17 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
|
||||
struct mgcp_client *mgcp_client_init(void *ctx,
|
||||
struct mgcp_client_conf *conf);
|
||||
int mgcp_client_connect(struct mgcp_client *mgcp);
|
||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
|
||||
void mgcp_client_disconnect(struct mgcp_client *mgcp);
|
||||
|
||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
|
||||
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
|
||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp);
|
||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp) OSMO_DEPRECATED("deprecated, returns 0");
|
||||
|
||||
int mgcp_client_next_endpoint(struct mgcp_client *client);
|
||||
void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client);
|
||||
const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp);
|
||||
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,
|
||||
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. */
|
||||
@@ -132,20 +162,6 @@ int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
|
||||
|
||||
enum mgcp_connection_mode;
|
||||
|
||||
struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
|
||||
uint16_t rtp_endpoint, unsigned int call_id,
|
||||
enum mgcp_connection_mode mode)
|
||||
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
|
||||
|
||||
struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
|
||||
uint16_t rtp_endpoint, const char *rtp_conn_addr,
|
||||
uint16_t rtp_port, enum mgcp_connection_mode mode)
|
||||
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
|
||||
|
||||
struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
|
||||
unsigned int call_id)
|
||||
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
|
||||
|
||||
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);
|
||||
|
||||
@@ -156,7 +172,9 @@ static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
|
||||
}
|
||||
|
||||
enum mgcp_codecs map_str_to_codec(const char *str);
|
||||
unsigned int map_codec_to_pt(struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
enum mgcp_codecs codec);
|
||||
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
unsigned int pt);
|
||||
|
||||
const char *mgcp_client_name(const struct mgcp_client *mgcp);
|
||||
|
54
include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
Normal file
54
include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* FSM to manage multiple connections of an MGW endpoint */
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
|
||||
|
||||
#define LOG_MGCPC_EP(ep, level, fmt, args...) do { \
|
||||
LOGPFSML(ep->fi, level, "%s " fmt, \
|
||||
osmo_mgcpc_ep_name(ep), ## args); \
|
||||
} while(0)
|
||||
|
||||
struct osmo_mgcpc_ep;
|
||||
struct osmo_mgcpc_ep_ci;
|
||||
struct osmo_tdef;
|
||||
|
||||
struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,
|
||||
struct mgcp_client *mgcp_client,
|
||||
const struct osmo_tdef *T_defs,
|
||||
const char *fsm_id,
|
||||
const char *endpoint_str_fmt, ...);
|
||||
|
||||
struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep, const char *label_fmt, ...);
|
||||
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
|
||||
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);
|
||||
|
||||
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,
|
||||
enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
|
||||
struct osmo_fsm_inst *notify,
|
||||
uint32_t event_success, uint32_t event_failure,
|
||||
void *notify_data);
|
||||
|
||||
void osmo_mgcpc_ep_cancel_notify(struct osmo_mgcpc_ep *ep, struct osmo_fsm_inst *notify);
|
||||
struct osmo_mgcpc_ep *osmo_mgcpc_ep_ci_ep(struct osmo_mgcpc_ep_ci *ci);
|
||||
|
||||
/*! Dispatch a DLCX for the given connection.
|
||||
* \param ci Connection identifier as obtained from osmo_mgcpc_ep_ci_add().
|
||||
*/
|
||||
static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
|
||||
{
|
||||
osmo_mgcpc_ep_ci_request(ci, MGCP_VERB_DLCX, NULL, NULL, 0, 0, NULL);
|
||||
}
|
||||
|
||||
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_ci_name(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[];
|
||||
static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
|
||||
{ return get_value_string(osmo_mgcp_verb_names, val); }
|
@@ -8,32 +8,59 @@
|
||||
* (either remote or local). It is used to pass parameters (local) to the FSM
|
||||
* and get responses (remote) from the FSM as pointer attached to the FSM
|
||||
* event.
|
||||
*
|
||||
*
|
||||
* When modifiying a connection, the endpoint and call_id members may be left
|
||||
* unpopulated. The call_id field is ignored in this case. If an endpoint
|
||||
* identifier is supplied it is checked against the internal state to make
|
||||
* sure it is correct. */
|
||||
struct mgcp_conn_peer {
|
||||
/*!< RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
|
||||
/*!< RTP connection IP-Port (optional) */
|
||||
/*! RTP connection IP-Port (optional) */
|
||||
uint16_t port;
|
||||
|
||||
/*!< RTP endpoint */
|
||||
/*! RTP endpoint */
|
||||
char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||
|
||||
/*!< CALL ID (unique per connection) */
|
||||
/*! CALL ID (unique per connection) */
|
||||
unsigned int call_id;
|
||||
|
||||
/*!< RTP packetization interval (optional) */
|
||||
/*! RTP packetization interval (optional) */
|
||||
unsigned int ptime;
|
||||
|
||||
/*!< RTP codec list (optional) */
|
||||
/*! RTP codec list (optional) */
|
||||
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
|
||||
|
||||
/*!< Number of codecs in RTP codec list (optional) */
|
||||
/*! Number of codecs in RTP codec list (optional) */
|
||||
unsigned int codecs_len;
|
||||
|
||||
/*! RTP payload type map (optional, only needed when payload types are
|
||||
* used that differ from what IANA/3GPP defines) */
|
||||
struct ptmap ptmap[MGCP_MAX_CODECS];
|
||||
|
||||
/*! RTP payload type map length (optional, only needed when payload
|
||||
* types are used that differ from what IANA/3GPP defines) */
|
||||
unsigned int ptmap_len;
|
||||
|
||||
/*! If nonzero, send 'X-Osmo-IGN:' header. This is useful e.g. for SCCPlite MSCs where the MSC is
|
||||
* known to issue incoherent or unknown CallIDs / to issue CRCX commands with a different domain
|
||||
* name than the BSC. An OsmoMGW will then ignore these and not fail on mismatches. */
|
||||
uint32_t x_osmo_ign;
|
||||
|
||||
/*! send 'X-Osmux: %d' header (or "*" as wildcard). */
|
||||
bool x_osmo_osmux_use;
|
||||
/*! -1 means send wildcard. */
|
||||
int x_osmo_osmux_cid;
|
||||
|
||||
/*! If left MGCP_CONN_NONE, use MGCP_CONN_RECV_ONLY or MGCP_CONN_RECV_SEND, depending on whether an audio RTP
|
||||
* address is set. If != MGCP_CONN_NONE, force this conn mode. */
|
||||
enum mgcp_connection_mode conn_mode;
|
||||
|
||||
/*! If the codec requires additional format parameters (fmtp), those cann be set here, see also
|
||||
* mgcp_common.h */
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
|
||||
@@ -42,3 +69,6 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
|
||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
|
||||
|
||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
|
||||
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
|
||||
|
||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
|
||||
|
@@ -4,13 +4,19 @@
|
||||
|
||||
#define MSGB_CB_MGCP_TRANS_ID 0
|
||||
|
||||
/* Struct that holds one endpoint name */
|
||||
struct reset_ep {
|
||||
struct llist_head list;
|
||||
char name[MGCP_ENDPOINT_MAXLEN];
|
||||
};
|
||||
|
||||
struct mgcp_client {
|
||||
struct mgcp_client_conf actual;
|
||||
uint32_t remote_addr;
|
||||
struct osmo_wqueue wq;
|
||||
mgcp_trans_id_t next_trans_id;
|
||||
struct llist_head responses_pending;
|
||||
struct llist_head inuse_endpoints;
|
||||
struct mgcp_client_pool *pool;
|
||||
};
|
||||
|
||||
struct mgcp_inuse_endpoint {
|
||||
|
11
include/osmocom/mgcp_client/mgcp_client_pool.h
Normal file
11
include/osmocom/mgcp_client/mgcp_client_pool.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
struct mgcp_client;
|
||||
struct mgcp_client_pool;
|
||||
|
||||
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
|
||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
|
||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
|
||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
|
||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
|
||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
|
45
include/osmocom/mgcp_client/mgcp_client_pool_internal.h
Normal file
45
include/osmocom/mgcp_client/mgcp_client_pool_internal.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
/* Struct to handle a member of a pool of MGWs. */
|
||||
struct mgcp_client_pool_member {
|
||||
struct llist_head list;
|
||||
|
||||
/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
|
||||
* the log. */
|
||||
unsigned int nr;
|
||||
|
||||
/* MGCP client configuration, this is not the running configuration, when mgcp_client_init() is executed, a
|
||||
* copy of this config is created. */
|
||||
struct mgcp_client_conf conf;
|
||||
|
||||
/* MGCP client descriptor, will be automatically allocated when mgcp_client_pool_connect() is called. (the MGCP
|
||||
* client is connected when this pointer is populated) */
|
||||
struct mgcp_client *client;
|
||||
|
||||
/* A pool member may be set as 'blocked' from the VTY, this means that the pool member may still work and serve
|
||||
* ongoing calls, but it won't be picked from the pool anymore. */
|
||||
bool blocked;
|
||||
|
||||
/* Reference counter to count how often this pool member is currently picked. */
|
||||
unsigned int refcount;
|
||||
};
|
||||
|
||||
/* Struct to handle a pool of MGWs. (Use _pool functions) */
|
||||
struct mgcp_client_pool {
|
||||
|
||||
/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
|
||||
* mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
|
||||
struct mgcp_client *mgcp_client_single;
|
||||
|
||||
/* A list that manages the pool members (see above) */
|
||||
struct llist_head pool;
|
||||
|
||||
/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
|
||||
* mgcp_client_pool_vty_init() */
|
||||
char *vty_indent;
|
||||
|
||||
/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
|
||||
struct cmd_node *vty_node;
|
||||
};
|
||||
|
||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
|
@@ -1,10 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: Osmocom legacy Media Gateway Control Protocol library
|
||||
Description: C Utility Library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -losmo-legacy-mgcp
|
||||
Cflags: -I${includedir}/
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,11 +17,9 @@
|
||||
|
||||
app_configs = {
|
||||
"osmo-mgw": ["doc/examples/osmo-mgw/osmo-mgw.cfg"],
|
||||
"osmo-bsc_mgcp": ["doc/examples/osmo-bsc_mgcp/mgcp.cfg"],
|
||||
}
|
||||
|
||||
apps = [(4243, "src/osmo-mgw/osmo-mgw", "OsmoMGW", "osmo-mgw"),
|
||||
(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "OpenBSC MGCP", "osmo-bsc_mgcp"),
|
||||
]
|
||||
|
||||
vty_command = ["./src/osmo-mgw/osmo-mgw", "-c",
|
||||
|
@@ -21,13 +21,11 @@ AM_LDFLAGS = \
|
||||
|
||||
# Libraries
|
||||
SUBDIRS = \
|
||||
libosmo-legacy-mgcp \
|
||||
libosmo-mgcp-client \
|
||||
libosmo-mgcp \
|
||||
$(NULL)
|
||||
|
||||
# Programs
|
||||
SUBDIRS += \
|
||||
osmo-bsc_mgcp \
|
||||
osmo-mgw \
|
||||
$(NULL)
|
||||
|
@@ -1,51 +0,0 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBBCG729_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(LIBBCG729_LIBS) \
|
||||
$(LIBRARY_GSM) \
|
||||
$(NULL)
|
||||
|
||||
# This is not at all related to the release version, but a range of supported
|
||||
# API versions. Read TODO_RELEASE in the source tree's root!
|
||||
LEGACY_MGCP_LIBVERSION=0:1:0
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libosmo-legacy-mgcp.la \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
g711common.h \
|
||||
$(NULL)
|
||||
|
||||
libosmo_legacy_mgcp_la_SOURCES = \
|
||||
mgcp_common.c \
|
||||
mgcp_protocol.c \
|
||||
mgcp_network.c \
|
||||
mgcp_vty.c \
|
||||
mgcp_osmux.c \
|
||||
mgcp_sdp.c \
|
||||
$(NULL)
|
||||
if BUILD_MGCP_TRANSCODING
|
||||
libosmo_legacy_mgcp_la_SOURCES += \
|
||||
mgcp_transcode.c \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
libosmo_legacy_mgcp_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LEGACY_MGCP_LIBVERSION)
|
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* PCM - A-Law conversion
|
||||
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
|
||||
*
|
||||
* Wrapper for linphone Codec class by Simon Morlat <simon.morlat@linphone.org>
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
static inline int val_seg(int val)
|
||||
{
|
||||
int r = 0;
|
||||
val >>= 7; /*7 = 4 + 3*/
|
||||
if (val & 0xf0) {
|
||||
val >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (val & 0x0c) {
|
||||
val >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (val & 0x02)
|
||||
r += 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
|
||||
*
|
||||
* s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
|
||||
*
|
||||
* Linear Input Code Compressed Code
|
||||
* ------------------------ ---------------
|
||||
* 0000000wxyza 000wxyz
|
||||
* 0000001wxyza 001wxyz
|
||||
* 000001wxyzab 010wxyz
|
||||
* 00001wxyzabc 011wxyz
|
||||
* 0001wxyzabcd 100wxyz
|
||||
* 001wxyzabcde 101wxyz
|
||||
* 01wxyzabcdef 110wxyz
|
||||
* 1wxyzabcdefg 111wxyz
|
||||
*
|
||||
* For further information see John C. Bellamy's Digital Telephony, 1982,
|
||||
* John Wiley & Sons, pps 98-111 and 472-476.
|
||||
* G711 is designed for 13 bits input signal, this function add extra shifting to take this into account.
|
||||
*/
|
||||
|
||||
static inline unsigned char s16_to_alaw(int pcm_val)
|
||||
{
|
||||
int mask;
|
||||
int seg;
|
||||
unsigned char aval;
|
||||
|
||||
if (pcm_val >= 0) {
|
||||
mask = 0xD5;
|
||||
} else {
|
||||
mask = 0x55;
|
||||
pcm_val = -pcm_val;
|
||||
if (pcm_val > 0x7fff)
|
||||
pcm_val = 0x7fff;
|
||||
}
|
||||
|
||||
if (pcm_val < 256) /*256 = 32 << 3*/
|
||||
aval = pcm_val >> 4; /*4 = 1 + 3*/
|
||||
else {
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
seg = val_seg(pcm_val);
|
||||
aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
|
||||
}
|
||||
return aval ^ mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
|
||||
*
|
||||
*/
|
||||
static inline int alaw_to_s16(unsigned char a_val)
|
||||
{
|
||||
int t;
|
||||
int seg;
|
||||
|
||||
a_val ^= 0x55;
|
||||
t = a_val & 0x7f;
|
||||
if (t < 16)
|
||||
t = (t << 4) + 8;
|
||||
else {
|
||||
seg = (t >> 4) & 0x07;
|
||||
t = ((t & 0x0f) << 4) + 0x108;
|
||||
t <<= seg -1;
|
||||
}
|
||||
return ((a_val & 0x80) ? t : -t);
|
||||
}
|
||||
/*
|
||||
* s16_to_ulaw() - Convert a linear PCM value to u-law
|
||||
*
|
||||
* In order to simplify the encoding process, the original linear magnitude
|
||||
* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
|
||||
* (33 - 8191). The result can be seen in the following encoding table:
|
||||
*
|
||||
* Biased Linear Input Code Compressed Code
|
||||
* ------------------------ ---------------
|
||||
* 00000001wxyza 000wxyz
|
||||
* 0000001wxyzab 001wxyz
|
||||
* 000001wxyzabc 010wxyz
|
||||
* 00001wxyzabcd 011wxyz
|
||||
* 0001wxyzabcde 100wxyz
|
||||
* 001wxyzabcdef 101wxyz
|
||||
* 01wxyzabcdefg 110wxyz
|
||||
* 1wxyzabcdefgh 111wxyz
|
||||
*
|
||||
* Each biased linear code has a leading 1 which identifies the segment
|
||||
* number. The value of the segment number is equal to 7 minus the number
|
||||
* of leading 0's. The quantization interval is directly available as the
|
||||
* four bits wxyz. * The trailing bits (a - h) are ignored.
|
||||
*
|
||||
* Ordinarily the complement of the resulting code word is used for
|
||||
* transmission, and so the code word is complemented before it is returned.
|
||||
*
|
||||
* For further information see John C. Bellamy's Digital Telephony, 1982,
|
||||
* John Wiley & Sons, pps 98-111 and 472-476.
|
||||
*/
|
||||
|
||||
static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
|
||||
{
|
||||
int mask;
|
||||
int seg;
|
||||
unsigned char uval;
|
||||
|
||||
if (pcm_val < 0) {
|
||||
pcm_val = 0x84 - pcm_val;
|
||||
mask = 0x7f;
|
||||
} else {
|
||||
pcm_val += 0x84;
|
||||
mask = 0xff;
|
||||
}
|
||||
if (pcm_val > 0x7fff)
|
||||
pcm_val = 0x7fff;
|
||||
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
seg = val_seg(pcm_val);
|
||||
|
||||
/*
|
||||
* Combine the sign, segment, quantization bits;
|
||||
* and complement the code word.
|
||||
*/
|
||||
uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
|
||||
return uval ^ mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
|
||||
*
|
||||
* First, a biased linear code is derived from the code word. An unbiased
|
||||
* output can then be obtained by subtracting 33 from the biased code.
|
||||
*
|
||||
* Note that this function expects to be passed the complement of the
|
||||
* original code word. This is in keeping with ISDN conventions.
|
||||
*/
|
||||
static inline int ulaw_to_s16(unsigned char u_val)
|
||||
{
|
||||
int t;
|
||||
|
||||
/* Complement to obtain normal u-law value. */
|
||||
u_val = ~u_val;
|
||||
|
||||
/*
|
||||
* Extract and bias the quantization bits. Then
|
||||
* shift up by the segment number and subtract out the bias.
|
||||
*/
|
||||
t = ((u_val & 0x0f) << 3) + 0x84;
|
||||
t <<= (u_val & 0x70) >> 4;
|
||||
|
||||
return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
/* Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* Implementations useful both for the MGCP GW as well as MGCP GW clients */
|
||||
|
||||
/*
|
||||
* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* 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 <errno.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/legacy_mgcp/mgcp.h>
|
||||
|
||||
const struct value_string mgcp_connection_mode_strs[] = {
|
||||
{ MGCP_CONN_NONE, "none" },
|
||||
{ MGCP_CONN_RECV_SEND, "sendrecv" },
|
||||
{ MGCP_CONN_SEND_ONLY, "sendonly" },
|
||||
{ MGCP_CONN_RECV_ONLY, "recvonly" },
|
||||
{ MGCP_CONN_LOOPBACK, "loopback" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Ensure that the msg->l2h is NUL terminated. */
|
||||
int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
{
|
||||
unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
|
||||
if (tail[-1] == '\0')
|
||||
/* nothing to do */;
|
||||
else if (msgb_tailroom(msg) > 0)
|
||||
tail[0] = '\0';
|
||||
else if (tail[-1] == '\r' || tail[-1] == '\n')
|
||||
tail[-1] = '\0';
|
||||
else {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
|
||||
"Length: %d, Buffer size: %d\n",
|
||||
msgb_l2len(msg), msg->data_len);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,588 +0,0 @@
|
||||
/*
|
||||
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
|
||||
* (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
|
||||
* All rights not specifically granted under this license are 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* for printf */
|
||||
#include <string.h> /* for memcpy */
|
||||
#include <stdlib.h> /* for abs */
|
||||
#include <inttypes.h> /* for PRIu64 */
|
||||
#include <netinet/in.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
|
||||
#include <osmocom/legacy_mgcp/mgcp.h>
|
||||
#include <osmocom/legacy_mgcp/mgcp_internal.h>
|
||||
#include <osmocom/legacy_mgcp/osmux.h>
|
||||
|
||||
static struct osmo_fd osmux_fd;
|
||||
|
||||
static LLIST_HEAD(osmux_handle_list);
|
||||
|
||||
struct osmux_handle {
|
||||
struct llist_head head;
|
||||
struct osmux_in_handle *in;
|
||||
struct in_addr rem_addr;
|
||||
int rem_port;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
static void *osmux;
|
||||
|
||||
static void osmux_deliver(struct msgb *batch_msg, void *data)
|
||||
{
|
||||
struct osmux_handle *handle = data;
|
||||
struct sockaddr_in out = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = handle->rem_port,
|
||||
};
|
||||
|
||||
memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
|
||||
sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
|
||||
(struct sockaddr *)&out, sizeof(out));
|
||||
msgb_free(batch_msg);
|
||||
}
|
||||
|
||||
static struct osmux_handle *
|
||||
osmux_handle_find_get(struct in_addr *addr, int rem_port)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
|
||||
/* Lookup for existing OSMUX handle for this destination address. */
|
||||
llist_for_each_entry(h, &osmux_handle_list, head) {
|
||||
if (memcmp(&h->rem_addr, addr, sizeof(struct in_addr)) == 0 &&
|
||||
h->rem_port == rem_port) {
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "using existing OSMUX handle "
|
||||
"for addr=%s:%d\n",
|
||||
inet_ntoa(*addr), ntohs(rem_port));
|
||||
h->refcnt++;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void osmux_handle_put(struct osmux_in_handle *in)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
|
||||
/* Lookup for existing OSMUX handle for this destination address. */
|
||||
llist_for_each_entry(h, &osmux_handle_list, head) {
|
||||
if (h->in == in) {
|
||||
if (--h->refcnt == 0) {
|
||||
LOGP(DLMGCP, LOGL_INFO,
|
||||
"Releasing unused osmux handle for %s:%d\n",
|
||||
inet_ntoa(h->rem_addr),
|
||||
ntohs(h->rem_port));
|
||||
LOGP(DLMGCP, LOGL_INFO, "Stats: "
|
||||
"input RTP msgs: %u bytes: %"PRIu64" "
|
||||
"output osmux msgs: %u bytes: %"PRIu64"\n",
|
||||
in->stats.input_rtp_msgs,
|
||||
in->stats.input_rtp_bytes,
|
||||
in->stats.output_osmux_msgs,
|
||||
in->stats.output_osmux_bytes);
|
||||
llist_del(&h->head);
|
||||
osmux_xfrm_input_fini(h->in);
|
||||
talloc_free(h);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot find Osmux input handle %p\n", in);
|
||||
}
|
||||
|
||||
static struct osmux_handle *
|
||||
osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
|
||||
h = talloc_zero(osmux, struct osmux_handle);
|
||||
if (!h)
|
||||
return NULL;
|
||||
h->rem_addr = *addr;
|
||||
h->rem_port = rem_port;
|
||||
h->refcnt++;
|
||||
|
||||
h->in = talloc_zero(h, struct osmux_in_handle);
|
||||
if (!h->in) {
|
||||
talloc_free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h->in->osmux_seq = 0; /* sequence number to start OSmux message from */
|
||||
h->in->batch_factor = cfg->osmux_batch;
|
||||
/* If batch size is zero, the library defaults to 1470 bytes. */
|
||||
h->in->batch_size = cfg->osmux_batch_size;
|
||||
h->in->deliver = osmux_deliver;
|
||||
osmux_xfrm_input_init(h->in);
|
||||
h->in->data = h;
|
||||
|
||||
llist_add(&h->head, &osmux_handle_list);
|
||||
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "created new OSMUX handle for addr=%s:%d\n",
|
||||
inet_ntoa(*addr), ntohs(rem_port));
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct osmux_in_handle *
|
||||
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
|
||||
h = osmux_handle_find_get(addr, rem_port);
|
||||
if (h != NULL)
|
||||
return h->in;
|
||||
|
||||
h = osmux_handle_alloc(cfg, addr, rem_port);
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
return h->in;
|
||||
}
|
||||
|
||||
int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp)
|
||||
{
|
||||
int ret;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = msgb_alloc(4096, "RTP");
|
||||
if (!msg)
|
||||
return 0;
|
||||
|
||||
memcpy(msg->data, buf, rc);
|
||||
msgb_put(msg, rc);
|
||||
|
||||
while ((ret = osmux_xfrm_input(endp->osmux.in, msg, endp->osmux.cid)) > 0) {
|
||||
/* batch full, build and deliver it */
|
||||
osmux_xfrm_input_deliver(endp->osmux.in);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mgcp_endpoint *
|
||||
endpoint_lookup(struct mgcp_config *cfg, int cid,
|
||||
struct in_addr *from_addr, int type)
|
||||
{
|
||||
struct mgcp_endpoint *tmp = NULL;
|
||||
int i;
|
||||
|
||||
/* Lookup for the endpoint that corresponds to this port */
|
||||
for (i=0; i<cfg->trunk.number_endpoints; i++) {
|
||||
struct in_addr *this;
|
||||
|
||||
tmp = &cfg->trunk.endpoints[i];
|
||||
|
||||
if (!tmp->allocated)
|
||||
continue;
|
||||
|
||||
switch(type) {
|
||||
case MGCP_DEST_NET:
|
||||
this = &tmp->net_end.addr;
|
||||
break;
|
||||
case MGCP_DEST_BTS:
|
||||
this = &tmp->bts_end.addr;
|
||||
break;
|
||||
default:
|
||||
/* Should not ever happen */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tmp->osmux.cid == cid && this->s_addr == from_addr->s_addr)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n", cid);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void scheduled_tx_net_cb(struct msgb *msg, void *data)
|
||||
{
|
||||
struct mgcp_endpoint *endp = data;
|
||||
struct sockaddr_in addr = {
|
||||
.sin_addr = endp->net_end.addr,
|
||||
.sin_port = endp->net_end.rtp_port,
|
||||
};
|
||||
|
||||
endp->bts_end.octets += msg->len;
|
||||
endp->bts_end.packets++;
|
||||
|
||||
mgcp_send(endp, MGCP_DEST_NET, 1, &addr, (char *)msg->data, msg->len);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
|
||||
{
|
||||
struct mgcp_endpoint *endp = data;
|
||||
struct sockaddr_in addr = {
|
||||
.sin_addr = endp->bts_end.addr,
|
||||
.sin_port = endp->bts_end.rtp_port,
|
||||
};
|
||||
|
||||
endp->net_end.octets += msg->len;
|
||||
endp->net_end.packets++;
|
||||
|
||||
mgcp_send(endp, MGCP_DEST_BTS, 1, &addr, (char *)msg->data, msg->len);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
|
||||
{
|
||||
struct msgb *msg;
|
||||
socklen_t slen = sizeof(*addr);
|
||||
int ret;
|
||||
|
||||
msg = msgb_alloc(4096, "OSMUX");
|
||||
if (!msg) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot allocate message\n");
|
||||
return NULL;
|
||||
}
|
||||
ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0,
|
||||
(struct sockaddr *)addr, &slen);
|
||||
if (ret <= 0) {
|
||||
msgb_free(msg);
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot receive message\n");
|
||||
return NULL;
|
||||
}
|
||||
msgb_put(msg, ret);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
#define osmux_chunk_length(msg, rem) (rem - msg->len);
|
||||
|
||||
int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmux_hdr *osmuxh;
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_config *cfg = ofd->data;
|
||||
uint32_t rem;
|
||||
|
||||
msg = osmux_recv(ofd, &addr);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
/* not any further processing dummy messages */
|
||||
if (msg->data[0] == MGCP_DUMMY_LOAD)
|
||||
goto out;
|
||||
|
||||
rem = msg->len;
|
||||
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/* Yes, we use MGCP_DEST_NET to locate the origin */
|
||||
endp = endpoint_lookup(cfg, osmuxh->circuit_id,
|
||||
&addr.sin_addr, MGCP_DEST_NET);
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find an endpoint for circuit_id=%d\n",
|
||||
osmuxh->circuit_id);
|
||||
goto out;
|
||||
}
|
||||
endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
|
||||
endp->osmux.stats.chunks++;
|
||||
rem = msg->len;
|
||||
|
||||
osmux_xfrm_output_sched(&endp->osmux.out, osmuxh);
|
||||
}
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is called from the bsc-nat */
|
||||
static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
|
||||
struct msgb *msg)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
uint8_t osmux_cid;
|
||||
|
||||
if (msg->len < 1 + sizeof(osmux_cid)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Discarding truncated Osmux dummy load\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Received Osmux dummy load from %s\n",
|
||||
inet_ntoa(addr->sin_addr));
|
||||
|
||||
if (!cfg->osmux) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"bsc wants to use Osmux but bsc-nat did not request it\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* extract the osmux CID from the dummy message */
|
||||
memcpy(&osmux_cid, &msg->data[1], sizeof(osmux_cid));
|
||||
|
||||
endp = endpoint_lookup(cfg, osmux_cid, &addr->sin_addr, MGCP_DEST_BTS);
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find endpoint for Osmux CID %d\n", osmux_cid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (endp->osmux.state == OSMUX_STATE_ENABLED)
|
||||
goto out;
|
||||
|
||||
if (osmux_enable_endpoint(endp, &addr->sin_addr, addr->sin_port) < 0 ) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Could not enable osmux in endpoint %d\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
goto out;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_INFO, "Enabling osmux in endpoint %d for %s:%u\n",
|
||||
ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr),
|
||||
ntohs(addr->sin_port));
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmux_hdr *osmuxh;
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_config *cfg = ofd->data;
|
||||
uint32_t rem;
|
||||
|
||||
msg = osmux_recv(ofd, &addr);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
/* not any further processing dummy messages */
|
||||
if (msg->data[0] == MGCP_DUMMY_LOAD)
|
||||
return osmux_handle_dummy(cfg, &addr, msg);
|
||||
|
||||
rem = msg->len;
|
||||
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/* Yes, we use MGCP_DEST_BTS to locate the origin */
|
||||
endp = endpoint_lookup(cfg, osmuxh->circuit_id,
|
||||
&addr.sin_addr, MGCP_DEST_BTS);
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find an endpoint for circuit_id=%d\n",
|
||||
osmuxh->circuit_id);
|
||||
goto out;
|
||||
}
|
||||
endp->osmux.stats.octets += osmux_chunk_length(msg, rem);
|
||||
endp->osmux.stats.chunks++;
|
||||
rem = msg->len;
|
||||
|
||||
osmux_xfrm_output_sched(&endp->osmux.out, osmuxh);
|
||||
}
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmux_init(int role, struct mgcp_config *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch(role) {
|
||||
case OSMUX_ROLE_BSC:
|
||||
osmux_fd.cb = osmux_read_from_bsc_nat_cb;
|
||||
break;
|
||||
case OSMUX_ROLE_BSC_NAT:
|
||||
osmux_fd.cb = osmux_read_from_bsc_cb;
|
||||
break;
|
||||
default:
|
||||
LOGP(DLMGCP, LOGL_ERROR, "wrong role for OSMUX\n");
|
||||
return -1;
|
||||
}
|
||||
osmux_fd.data = cfg;
|
||||
|
||||
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
|
||||
if (ret < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket\n");
|
||||
return ret;
|
||||
}
|
||||
mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
|
||||
osmux_fd.when |= BSC_FD_READ;
|
||||
|
||||
ret = osmo_fd_register(&osmux_fd);
|
||||
if (ret < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot register OSMUX socket\n");
|
||||
return ret;
|
||||
}
|
||||
cfg->osmux_init = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port)
|
||||
{
|
||||
/* If osmux is enabled, initialize the output handler. This handler is
|
||||
* used to reconstruct the RTP flow from osmux. The RTP SSRC is
|
||||
* allocated based on the circuit ID (endp->osmux.cid), which is unique
|
||||
* in the local scope to the BSC/BSC-NAT. We use it to divide the RTP
|
||||
* SSRC space (2^32) by the 256 possible circuit IDs, then randomly
|
||||
* select one value from that window. Thus, we have no chance to have
|
||||
* overlapping RTP SSRC traveling to the BTSes behind the BSC,
|
||||
* similarly, for flows traveling to the MSC.
|
||||
*/
|
||||
static const uint32_t rtp_ssrc_winlen = UINT32_MAX / 256;
|
||||
|
||||
if (endp->osmux.state == OSMUX_STATE_DISABLED) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Endpoint %u didn't request Osmux\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
osmux_xfrm_output_init(&endp->osmux.out,
|
||||
(endp->osmux.cid * rtp_ssrc_winlen) +
|
||||
(random() % rtp_ssrc_winlen));
|
||||
|
||||
endp->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
|
||||
if (!endp->osmux.in) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot allocate input osmux handle\n");
|
||||
return -1;
|
||||
}
|
||||
if (!osmux_xfrm_input_open_circuit(endp->osmux.in, endp->osmux.cid,
|
||||
endp->cfg->osmux_dummy)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u\n",
|
||||
endp->osmux.cid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (endp->cfg->role) {
|
||||
case MGCP_BSC_NAT:
|
||||
endp->type = MGCP_OSMUX_BSC_NAT;
|
||||
osmux_xfrm_output_set_tx_cb(&endp->osmux.out,
|
||||
scheduled_tx_net_cb, endp);
|
||||
break;
|
||||
case MGCP_BSC:
|
||||
endp->type = MGCP_OSMUX_BSC;
|
||||
osmux_xfrm_output_set_tx_cb(&endp->osmux.out,
|
||||
scheduled_tx_bts_cb, endp);
|
||||
break;
|
||||
}
|
||||
endp->osmux.state = OSMUX_STATE_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osmux_disable_endpoint(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGP(DLMGCP, LOGL_INFO, "Releasing endpoint %u using Osmux CID %u\n",
|
||||
ENDPOINT_NUMBER(endp), endp->osmux.cid);
|
||||
|
||||
/* We are closing, we don't need pending RTP packets to be transmitted */
|
||||
osmux_xfrm_output_set_tx_cb(&endp->osmux.out, NULL, NULL);
|
||||
osmux_xfrm_output_flush(&endp->osmux.out);
|
||||
|
||||
osmux_xfrm_input_close_circuit(endp->osmux.in, endp->osmux.cid);
|
||||
endp->osmux.state = OSMUX_STATE_DISABLED;
|
||||
endp->osmux.cid = -1;
|
||||
osmux_handle_put(endp->osmux.in);
|
||||
}
|
||||
|
||||
void osmux_release_cid(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (endp->osmux.allocated_cid >= 0)
|
||||
osmux_put_cid(endp->osmux.allocated_cid);
|
||||
endp->osmux.allocated_cid = -1;
|
||||
}
|
||||
|
||||
void osmux_allocate_cid(struct mgcp_endpoint *endp)
|
||||
{
|
||||
osmux_release_cid(endp);
|
||||
endp->osmux.allocated_cid = osmux_get_cid();
|
||||
}
|
||||
|
||||
/* We don't need to send the dummy load for osmux so often as another endpoint
|
||||
* may have already punched the hole in the firewall. This approach is simple
|
||||
* though.
|
||||
*/
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp)
|
||||
{
|
||||
char buf[1 + sizeof(uint8_t)];
|
||||
struct in_addr addr_unset = {};
|
||||
|
||||
buf[0] = MGCP_DUMMY_LOAD;
|
||||
memcpy(&buf[1], &endp->osmux.cid, sizeof(endp->osmux.cid));
|
||||
|
||||
/* Wait until we have the connection information from MDCX */
|
||||
if (memcmp(&endp->net_end.addr, &addr_unset, sizeof(addr_unset)) == 0)
|
||||
return 0;
|
||||
|
||||
if (endp->osmux.state == OSMUX_STATE_ACTIVATING) {
|
||||
if (osmux_enable_endpoint(endp, &endp->net_end.addr,
|
||||
htons(endp->cfg->osmux_port)) < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Could not activate osmux in endpoint %d\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
}
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Osmux CID %u for %s:%u is now enabled\n",
|
||||
endp->osmux.cid, inet_ntoa(endp->net_end.addr),
|
||||
endp->cfg->osmux_port);
|
||||
}
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"sending OSMUX dummy load to %s CID %u\n",
|
||||
inet_ntoa(endp->net_end.addr), endp->osmux.cid);
|
||||
|
||||
return mgcp_udp_send(osmux_fd.fd, &endp->net_end.addr,
|
||||
htons(endp->cfg->osmux_port), buf, sizeof(buf));
|
||||
}
|
||||
|
||||
/* bsc-nat allocates/releases the Osmux circuit ID */
|
||||
static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1) / 8];
|
||||
|
||||
int osmux_used_cid(void)
|
||||
{
|
||||
int i, j, used = 0;
|
||||
|
||||
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (osmux_cid_bitmap[i] & (1 << j))
|
||||
used += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
int osmux_get_cid(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (osmux_cid_bitmap[i] & (1 << j))
|
||||
continue;
|
||||
|
||||
osmux_cid_bitmap[i] |= (1 << j);
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"Allocating Osmux CID %u from pool\n", (i * 8) + j);
|
||||
return (i * 8) + j;
|
||||
}
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "All Osmux circuits are in use!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void osmux_put_cid(uint8_t osmux_cid)
|
||||
{
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
|
||||
osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,305 +0,0 @@
|
||||
/*
|
||||
* Some SDP file parsing...
|
||||
*
|
||||
* (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2014 by On-Waves
|
||||
* 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/legacy_mgcp/mgcp.h>
|
||||
#include <osmocom/legacy_mgcp/mgcp_internal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
struct sdp_rtp_map {
|
||||
/* the type */
|
||||
int payload_type;
|
||||
/* null, static or later dynamic codec name */
|
||||
char *codec_name;
|
||||
/* A pointer to the original line for later parsing */
|
||||
char *map_line;
|
||||
|
||||
int rate;
|
||||
int channels;
|
||||
};
|
||||
|
||||
int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
|
||||
int payload_type, const char *audio_name)
|
||||
{
|
||||
int rate = codec->rate;
|
||||
int channels = codec->channels;
|
||||
char audio_codec[64];
|
||||
|
||||
talloc_free(codec->subtype_name);
|
||||
codec->subtype_name = NULL;
|
||||
talloc_free(codec->audio_name);
|
||||
codec->audio_name = NULL;
|
||||
|
||||
if (payload_type != PTYPE_UNDEFINED)
|
||||
codec->payload_type = payload_type;
|
||||
|
||||
if (!audio_name) {
|
||||
switch (payload_type) {
|
||||
case 0: audio_name = "PCMU/8000/1"; break;
|
||||
case 3: audio_name = "GSM/8000/1"; break;
|
||||
case 8: audio_name = "PCMA/8000/1"; break;
|
||||
case 18: audio_name = "G729/8000/1"; break;
|
||||
default:
|
||||
/* Payload type is unknown, don't change rate and
|
||||
* channels. */
|
||||
/* TODO: return value? */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (sscanf(audio_name, "%63[^/]/%d/%d",
|
||||
audio_codec, &rate, &channels) < 1)
|
||||
return -EINVAL;
|
||||
|
||||
codec->rate = rate;
|
||||
codec->channels = channels;
|
||||
codec->subtype_name = talloc_strdup(ctx, audio_codec);
|
||||
codec->audio_name = talloc_strdup(ctx, audio_name);
|
||||
|
||||
if (!strcmp(audio_codec, "G729")) {
|
||||
codec->frame_duration_num = 10;
|
||||
codec->frame_duration_den = 1000;
|
||||
} else {
|
||||
codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
|
||||
codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
|
||||
}
|
||||
|
||||
if (payload_type < 0) {
|
||||
payload_type = 96;
|
||||
if (rate == 8000 && channels == 1) {
|
||||
if (!strcmp(audio_codec, "GSM"))
|
||||
payload_type = 3;
|
||||
else if (!strcmp(audio_codec, "PCMA"))
|
||||
payload_type = 8;
|
||||
else if (!strcmp(audio_codec, "PCMU"))
|
||||
payload_type = 0;
|
||||
else if (!strcmp(audio_codec, "G729"))
|
||||
payload_type = 18;
|
||||
}
|
||||
|
||||
codec->payload_type = payload_type;
|
||||
}
|
||||
|
||||
if (channels != 1)
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Channels != 1 in SDP: '%s'\n", audio_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < used; ++i) {
|
||||
switch (codecs[i].payload_type) {
|
||||
case 0:
|
||||
codecs[i].codec_name = "PCMU";
|
||||
codecs[i].rate = 8000;
|
||||
codecs[i].channels = 1;
|
||||
break;
|
||||
case 3:
|
||||
codecs[i].codec_name = "GSM";
|
||||
codecs[i].rate = 8000;
|
||||
codecs[i].channels = 1;
|
||||
break;
|
||||
case 8:
|
||||
codecs[i].codec_name = "PCMA";
|
||||
codecs[i].rate = 8000;
|
||||
codecs[i].channels = 1;
|
||||
break;
|
||||
case 18:
|
||||
codecs[i].codec_name = "G729";
|
||||
codecs[i].rate = 8000;
|
||||
codecs[i].channels = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used, int payload, char *audio_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < used; ++i) {
|
||||
char audio_codec[64];
|
||||
int rate = -1;
|
||||
int channels = -1;
|
||||
if (codecs[i].payload_type != payload)
|
||||
continue;
|
||||
if (sscanf(audio_name, "%63[^/]/%d/%d",
|
||||
audio_codec, &rate, &channels) < 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n", audio_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
codecs[i].map_line = talloc_strdup(ctx, audio_name);
|
||||
codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
|
||||
codecs[i].rate = rate;
|
||||
codecs[i].channels = channels;
|
||||
return;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload, audio_name);
|
||||
}
|
||||
|
||||
int is_codec_compatible(struct mgcp_endpoint *endp, struct sdp_rtp_map *codec)
|
||||
{
|
||||
char *bts_codec;
|
||||
char audio_codec[64];
|
||||
|
||||
if (!codec->codec_name)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* GSM, GSM/8000 and GSM/8000/1 should all be compatible.. let's go
|
||||
* by name first.
|
||||
*/
|
||||
bts_codec = endp->tcfg->audio_name;
|
||||
if (sscanf(bts_codec, "%63[^/]/%*d/%*d", audio_codec) < 1)
|
||||
return 0;
|
||||
|
||||
return strcasecmp(audio_codec, codec->codec_name) == 0;
|
||||
}
|
||||
|
||||
int mgcp_parse_sdp_data(struct mgcp_endpoint *endp, struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p)
|
||||
{
|
||||
struct sdp_rtp_map codecs[10];
|
||||
int codecs_used = 0;
|
||||
char *line;
|
||||
int maxptime = -1;
|
||||
int i;
|
||||
int codecs_assigned = 0;
|
||||
void *tmp_ctx = talloc_new(NULL);
|
||||
|
||||
memset(&codecs, 0, sizeof(codecs));
|
||||
|
||||
for_each_line(line, p->save) {
|
||||
switch (line[0]) {
|
||||
case 'o':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'v':
|
||||
/* skip these SDP attributes */
|
||||
break;
|
||||
case 'a': {
|
||||
int payload;
|
||||
int ptime, ptime2 = 0;
|
||||
char audio_name[64];
|
||||
|
||||
|
||||
if (sscanf(line, "a=rtpmap:%d %63s",
|
||||
&payload, audio_name) == 2) {
|
||||
codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
|
||||
} else if (sscanf(line, "a=ptime:%d-%d",
|
||||
&ptime, &ptime2) >= 1) {
|
||||
if (ptime2 > 0 && ptime2 != ptime)
|
||||
rtp->packet_duration_ms = 0;
|
||||
else
|
||||
rtp->packet_duration_ms = ptime;
|
||||
} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
|
||||
maxptime = ptime2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
int port, rc;
|
||||
|
||||
rc = sscanf(line, "m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",
|
||||
&port,
|
||||
&codecs[0].payload_type,
|
||||
&codecs[1].payload_type,
|
||||
&codecs[2].payload_type,
|
||||
&codecs[3].payload_type,
|
||||
&codecs[4].payload_type,
|
||||
&codecs[5].payload_type,
|
||||
&codecs[6].payload_type,
|
||||
&codecs[7].payload_type,
|
||||
&codecs[8].payload_type,
|
||||
&codecs[9].payload_type);
|
||||
if (rc >= 2) {
|
||||
rtp->rtp_port = htons(port);
|
||||
rtp->rtcp_port = htons(port + 1);
|
||||
codecs_used = rc - 1;
|
||||
codecs_initialize(tmp_ctx, codecs, codecs_used);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char ipv4[16];
|
||||
|
||||
if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
|
||||
inet_aton(ipv4, &rtp->addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (p->endp)
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Unhandled SDP option: '%c'/%d on 0x%x\n",
|
||||
line[0], line[0], ENDPOINT_NUMBER(p->endp));
|
||||
else
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Unhandled SDP option: '%c'/%d\n",
|
||||
line[0], line[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now select the primary and alt_codec */
|
||||
for (i = 0; i < codecs_used && codecs_assigned < 2; ++i) {
|
||||
struct mgcp_rtp_codec *codec = codecs_assigned == 0 ?
|
||||
&rtp->codec : &rtp->alt_codec;
|
||||
|
||||
if (endp->tcfg->no_audio_transcoding &&
|
||||
!is_codec_compatible(endp, &codecs[i])) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "Skipping codec %s\n",
|
||||
codecs[i].codec_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
mgcp_set_audio_info(p->cfg, codec,
|
||||
codecs[i].payload_type,
|
||||
codecs[i].map_line);
|
||||
codecs_assigned += 1;
|
||||
}
|
||||
|
||||
if (codecs_assigned > 0) {
|
||||
/* TODO/XXX: Store this per codec and derive it on use */
|
||||
if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den >
|
||||
rtp->codec.frame_duration_num * 1500) {
|
||||
/* more than 1 frame */
|
||||
rtp->packet_duration_ms = 0;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Got media info via SDP: port %d, payload %d (%s), "
|
||||
"duration %d, addr %s\n",
|
||||
ntohs(rtp->rtp_port), rtp->codec.payload_type,
|
||||
rtp->codec.subtype_name ? rtp->codec.subtype_name : "unknown",
|
||||
rtp->packet_duration_ms, inet_ntoa(rtp->addr));
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return codecs_assigned > 0;
|
||||
}
|
||||
|
@@ -1,611 +0,0 @@
|
||||
/*
|
||||
* (C) 2014 by On-Waves
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "g711common.h"
|
||||
|
||||
#include <osmocom/legacy_mgcp/mgcp.h>
|
||||
#include <osmocom/legacy_mgcp/mgcp_internal.h>
|
||||
#include <osmocom/legacy_mgcp/mgcp_transcode.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
|
||||
int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst)
|
||||
{
|
||||
struct mgcp_process_rtp_state *state = state_;
|
||||
if (dst)
|
||||
return (nsamples >= 0 ?
|
||||
nsamples / state->dst_samples_per_frame :
|
||||
1) * state->dst_frame_size;
|
||||
else
|
||||
return (nsamples >= 0 ?
|
||||
nsamples / state->src_samples_per_frame :
|
||||
1) * state->src_frame_size;
|
||||
}
|
||||
|
||||
static enum audio_format get_audio_format(const struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
if (codec->subtype_name) {
|
||||
if (!strcasecmp("GSM", codec->subtype_name))
|
||||
return AF_GSM;
|
||||
if (!strcasecmp("PCMA", codec->subtype_name))
|
||||
return AF_PCMA;
|
||||
if (!strcasecmp("PCMU", codec->subtype_name))
|
||||
return AF_PCMU;
|
||||
#ifdef HAVE_BCG729
|
||||
if (!strcasecmp("G729", codec->subtype_name))
|
||||
return AF_G729;
|
||||
#endif
|
||||
if (!strcasecmp("L16", codec->subtype_name))
|
||||
return AF_L16;
|
||||
}
|
||||
|
||||
switch (codec->payload_type) {
|
||||
case 0 /* PCMU */:
|
||||
return AF_PCMU;
|
||||
case 3 /* GSM */:
|
||||
return AF_GSM;
|
||||
case 8 /* PCMA */:
|
||||
return AF_PCMA;
|
||||
#ifdef HAVE_BCG729
|
||||
case 18 /* G.729 */:
|
||||
return AF_G729;
|
||||
#endif
|
||||
case 11 /* L16 */:
|
||||
return AF_L16;
|
||||
default:
|
||||
return AF_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static void l16_encode(short *sample, unsigned char *buf, size_t n)
|
||||
{
|
||||
for (; n > 0; --n, ++sample, buf += 2) {
|
||||
buf[0] = sample[0] >> 8;
|
||||
buf[1] = sample[0] & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void l16_decode(unsigned char *buf, short *sample, size_t n)
|
||||
{
|
||||
for (; n > 0; --n, ++sample, buf += 2)
|
||||
sample[0] = ((short)buf[0] << 8) | buf[1];
|
||||
}
|
||||
|
||||
static void alaw_encode(short *sample, unsigned char *buf, size_t n)
|
||||
{
|
||||
for (; n > 0; --n)
|
||||
*(buf++) = s16_to_alaw(*(sample++));
|
||||
}
|
||||
|
||||
static void alaw_decode(unsigned char *buf, short *sample, size_t n)
|
||||
{
|
||||
for (; n > 0; --n)
|
||||
*(sample++) = alaw_to_s16(*(buf++));
|
||||
}
|
||||
|
||||
static void ulaw_encode(short *sample, unsigned char *buf, size_t n)
|
||||
{
|
||||
for (; n > 0; --n)
|
||||
*(buf++) = s16_to_ulaw(*(sample++));
|
||||
}
|
||||
|
||||
static void ulaw_decode(unsigned char *buf, short *sample, size_t n)
|
||||
{
|
||||
for (; n > 0; --n)
|
||||
*(sample++) = ulaw_to_s16(*(buf++));
|
||||
}
|
||||
|
||||
static int processing_state_destructor(struct mgcp_process_rtp_state *state)
|
||||
{
|
||||
switch (state->src_fmt) {
|
||||
case AF_GSM:
|
||||
if (state->src.gsm_handle)
|
||||
gsm_destroy(state->src.gsm_handle);
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
if (state->src.g729_dec)
|
||||
closeBcg729DecoderChannel(state->src.g729_dec);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (state->dst_fmt) {
|
||||
case AF_GSM:
|
||||
if (state->dst.gsm_handle)
|
||||
gsm_destroy(state->dst.gsm_handle);
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
if (state->dst.g729_enc)
|
||||
closeBcg729EncoderChannel(state->dst.g729_enc);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mgcp_transcoding_setup(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct mgcp_rtp_end *src_end)
|
||||
{
|
||||
struct mgcp_process_rtp_state *state;
|
||||
enum audio_format src_fmt, dst_fmt;
|
||||
const struct mgcp_rtp_codec *dst_codec = &dst_end->codec;
|
||||
|
||||
/* cleanup first */
|
||||
if (dst_end->rtp_process_data) {
|
||||
talloc_free(dst_end->rtp_process_data);
|
||||
dst_end->rtp_process_data = NULL;
|
||||
}
|
||||
|
||||
if (!src_end)
|
||||
return 0;
|
||||
|
||||
const struct mgcp_rtp_codec *src_codec = &src_end->codec;
|
||||
|
||||
if (endp->tcfg->no_audio_transcoding) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Transcoding disabled on endpoint 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
src_fmt = get_audio_format(src_codec);
|
||||
dst_fmt = get_audio_format(dst_codec);
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Checking transcoding: %s (%d) -> %s (%d)\n",
|
||||
src_codec->subtype_name, src_codec->payload_type,
|
||||
dst_codec->subtype_name, dst_codec->payload_type);
|
||||
|
||||
if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) {
|
||||
if (!src_codec->subtype_name || !dst_codec->subtype_name)
|
||||
/* Not enough info, do nothing */
|
||||
return 0;
|
||||
|
||||
if (strcasecmp(src_codec->subtype_name, dst_codec->subtype_name) == 0)
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot transcode: %s codec not supported (%s -> %s).\n",
|
||||
src_fmt != AF_INVALID ? "destination" : "source",
|
||||
src_codec->audio_name, dst_codec->audio_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (src_codec->rate && dst_codec->rate && src_codec->rate != dst_codec->rate) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot transcode: rate conversion (%d -> %d) not supported.\n",
|
||||
src_codec->rate, dst_codec->rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state);
|
||||
talloc_set_destructor(state, processing_state_destructor);
|
||||
dst_end->rtp_process_data = state;
|
||||
|
||||
state->src_fmt = src_fmt;
|
||||
|
||||
switch (state->src_fmt) {
|
||||
case AF_L16:
|
||||
case AF_S16:
|
||||
state->src_frame_size = 80 * sizeof(short);
|
||||
state->src_samples_per_frame = 80;
|
||||
break;
|
||||
case AF_GSM:
|
||||
state->src_frame_size = sizeof(gsm_frame);
|
||||
state->src_samples_per_frame = 160;
|
||||
state->src.gsm_handle = gsm_create();
|
||||
if (!state->src.gsm_handle) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Failed to initialize GSM decoder.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
state->src_frame_size = 10;
|
||||
state->src_samples_per_frame = 80;
|
||||
state->src.g729_dec = initBcg729DecoderChannel();
|
||||
if (!state->src.g729_dec) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Failed to initialize G.729 decoder.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case AF_PCMU:
|
||||
case AF_PCMA:
|
||||
state->src_frame_size = 80;
|
||||
state->src_samples_per_frame = 80;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
state->dst_fmt = dst_fmt;
|
||||
|
||||
switch (state->dst_fmt) {
|
||||
case AF_L16:
|
||||
case AF_S16:
|
||||
state->dst_frame_size = 80*sizeof(short);
|
||||
state->dst_samples_per_frame = 80;
|
||||
break;
|
||||
case AF_GSM:
|
||||
state->dst_frame_size = sizeof(gsm_frame);
|
||||
state->dst_samples_per_frame = 160;
|
||||
state->dst.gsm_handle = gsm_create();
|
||||
if (!state->dst.gsm_handle) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Failed to initialize GSM encoder.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
state->dst_frame_size = 10;
|
||||
state->dst_samples_per_frame = 80;
|
||||
state->dst.g729_enc = initBcg729EncoderChannel();
|
||||
if (!state->dst.g729_enc) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Failed to initialize G.729 decoder.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case AF_PCMU:
|
||||
case AF_PCMA:
|
||||
state->dst_frame_size = 80;
|
||||
state->dst_samples_per_frame = 80;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst_end->force_output_ptime)
|
||||
state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end);
|
||||
|
||||
LOGP(DLMGCP, LOGL_INFO,
|
||||
"Initialized RTP processing on: 0x%x "
|
||||
"conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n",
|
||||
ENDPOINT_NUMBER(endp),
|
||||
src_fmt, src_codec->payload_type, src_codec->rate, src_end->fmtp_extra,
|
||||
dst_fmt, dst_codec->payload_type, dst_codec->rate, dst_end->fmtp_extra);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**audio_name,
|
||||
const char**fmtp_extra)
|
||||
{
|
||||
struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data;
|
||||
struct mgcp_rtp_codec *net_codec = &endp->net_end.codec;
|
||||
struct mgcp_rtp_codec *bts_codec = &endp->bts_end.codec;
|
||||
|
||||
if (!state || net_codec->payload_type < 0) {
|
||||
*payload_type = bts_codec->payload_type;
|
||||
*audio_name = bts_codec->audio_name;
|
||||
*fmtp_extra = endp->bts_end.fmtp_extra;
|
||||
return;
|
||||
}
|
||||
|
||||
*payload_type = net_codec->payload_type;
|
||||
*audio_name = net_codec->audio_name;
|
||||
*fmtp_extra = endp->net_end.fmtp_extra;
|
||||
}
|
||||
|
||||
static int decode_audio(struct mgcp_process_rtp_state *state,
|
||||
uint8_t **src, size_t *nbytes)
|
||||
{
|
||||
while (*nbytes >= state->src_frame_size) {
|
||||
if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Sample buffer too small: %zu > %zu.\n",
|
||||
state->sample_cnt + state->src_samples_per_frame,
|
||||
ARRAY_SIZE(state->samples));
|
||||
return -ENOSPC;
|
||||
}
|
||||
switch (state->src_fmt) {
|
||||
case AF_GSM:
|
||||
if (gsm_decode(state->src.gsm_handle,
|
||||
(gsm_byte *)*src, state->samples + state->sample_cnt) < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Failed to decode GSM.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt);
|
||||
break;
|
||||
#endif
|
||||
case AF_PCMU:
|
||||
ulaw_decode(*src, state->samples + state->sample_cnt,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
case AF_PCMA:
|
||||
alaw_decode(*src, state->samples + state->sample_cnt,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
case AF_S16:
|
||||
memmove(state->samples + state->sample_cnt, *src,
|
||||
state->src_frame_size);
|
||||
break;
|
||||
case AF_L16:
|
||||
l16_decode(*src, state->samples + state->sample_cnt,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*src += state->src_frame_size;
|
||||
*nbytes -= state->src_frame_size;
|
||||
state->sample_cnt += state->src_samples_per_frame;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_audio(struct mgcp_process_rtp_state *state,
|
||||
uint8_t *dst, size_t buf_size, size_t max_samples)
|
||||
{
|
||||
int nbytes = 0;
|
||||
size_t nsamples = 0;
|
||||
/* Encode samples into dst */
|
||||
while (nsamples + state->dst_samples_per_frame <= max_samples) {
|
||||
if (nbytes + state->dst_frame_size > buf_size) {
|
||||
if (nbytes > 0)
|
||||
break;
|
||||
|
||||
/* Not even one frame fits into the buffer */
|
||||
LOGP(DLMGCP, LOGL_INFO,
|
||||
"Encoding (RTP) buffer too small: %zu > %zu.\n",
|
||||
nbytes + state->dst_frame_size, buf_size);
|
||||
return -ENOSPC;
|
||||
}
|
||||
switch (state->dst_fmt) {
|
||||
case AF_GSM:
|
||||
gsm_encode(state->dst.gsm_handle,
|
||||
state->samples + state->sample_offs, dst);
|
||||
break;
|
||||
#ifdef HAVE_BCG729
|
||||
case AF_G729:
|
||||
bcg729Encoder(state->dst.g729_enc,
|
||||
state->samples + state->sample_offs, dst);
|
||||
break;
|
||||
#endif
|
||||
case AF_PCMU:
|
||||
ulaw_encode(state->samples + state->sample_offs, dst,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
case AF_PCMA:
|
||||
alaw_encode(state->samples + state->sample_offs, dst,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
case AF_S16:
|
||||
memmove(dst, state->samples + state->sample_offs,
|
||||
state->dst_frame_size);
|
||||
break;
|
||||
case AF_L16:
|
||||
l16_encode(state->samples + state->sample_offs, dst,
|
||||
state->src_samples_per_frame);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dst += state->dst_frame_size;
|
||||
nbytes += state->dst_frame_size;
|
||||
state->sample_offs += state->dst_samples_per_frame;
|
||||
nsamples += state->dst_samples_per_frame;
|
||||
}
|
||||
state->sample_cnt -= nsamples;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static struct mgcp_rtp_end *source_for_dest(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end)
|
||||
{
|
||||
if (&endp->bts_end == dst_end)
|
||||
return &endp->net_end;
|
||||
else if (&endp->net_end == dst_end)
|
||||
return &endp->bts_end;
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* With some modems we get offered multiple codecs
|
||||
* and we have selected one of them. It might not
|
||||
* be the right one and we need to detect this with
|
||||
* the first audio packets. One difficulty is that
|
||||
* we patch the rtp payload type in place, so we
|
||||
* need to discuss this.
|
||||
*/
|
||||
struct mgcp_process_rtp_state *check_transcode_state(
|
||||
struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
struct rtp_hdr *rtp_hdr)
|
||||
{
|
||||
struct mgcp_rtp_end *src_end;
|
||||
|
||||
/* Only deal with messages from net to bts */
|
||||
if (&endp->bts_end != dst_end)
|
||||
goto done;
|
||||
|
||||
src_end = source_for_dest(endp, dst_end);
|
||||
|
||||
/* Already patched */
|
||||
if (rtp_hdr->payload_type == dst_end->codec.payload_type)
|
||||
goto done;
|
||||
/* The payload we expect */
|
||||
if (rtp_hdr->payload_type == src_end->codec.payload_type)
|
||||
goto done;
|
||||
/* The matching alternate payload type? Then switch */
|
||||
if (rtp_hdr->payload_type == src_end->alt_codec.payload_type) {
|
||||
struct mgcp_config *cfg = endp->cfg;
|
||||
struct mgcp_rtp_codec tmp_codec = src_end->alt_codec;
|
||||
src_end->alt_codec = src_end->codec;
|
||||
src_end->codec = tmp_codec;
|
||||
cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end);
|
||||
cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end);
|
||||
}
|
||||
|
||||
done:
|
||||
return dst_end->rtp_process_data;
|
||||
}
|
||||
|
||||
int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size)
|
||||
{
|
||||
struct mgcp_process_rtp_state *state;
|
||||
const size_t rtp_hdr_size = sizeof(struct rtp_hdr);
|
||||
struct rtp_hdr *rtp_hdr = (struct rtp_hdr *) data;
|
||||
char *payload_data = (char *) &rtp_hdr->data[0];
|
||||
int payload_len = *len - rtp_hdr_size;
|
||||
uint8_t *src = (uint8_t *)payload_data;
|
||||
uint8_t *dst = (uint8_t *)payload_data;
|
||||
size_t nbytes = payload_len;
|
||||
size_t nsamples;
|
||||
size_t max_samples;
|
||||
uint32_t ts_no;
|
||||
int rc;
|
||||
|
||||
state = check_transcode_state(endp, dst_end, rtp_hdr);
|
||||
if (!state)
|
||||
return 0;
|
||||
|
||||
if (state->src_fmt == state->dst_fmt) {
|
||||
if (!state->dst_packet_duration)
|
||||
return 0;
|
||||
|
||||
/* TODO: repackage without transcoding */
|
||||
}
|
||||
|
||||
/* If the remaining samples do not fit into a fixed ptime,
|
||||
* a) discard them, if the next packet is much later
|
||||
* b) add silence and * send it, if the current packet is not
|
||||
* yet too late
|
||||
* c) append the sample data, if the timestamp matches exactly
|
||||
*/
|
||||
|
||||
/* TODO: check payload type (-> G.711 comfort noise) */
|
||||
|
||||
if (payload_len > 0) {
|
||||
ts_no = ntohl(rtp_hdr->timestamp);
|
||||
if (!state->is_running) {
|
||||
state->next_seq = ntohs(rtp_hdr->sequence);
|
||||
state->next_time = ts_no;
|
||||
state->is_running = 1;
|
||||
}
|
||||
|
||||
|
||||
if (state->sample_cnt > 0) {
|
||||
int32_t delta = ts_no - state->next_time;
|
||||
/* TODO: check sequence? reordering? packet loss? */
|
||||
|
||||
if (delta > state->sample_cnt) {
|
||||
/* There is a time gap between the last packet
|
||||
* and the current one. Just discard the
|
||||
* partial data that is left in the buffer.
|
||||
* TODO: This can be improved by adding silence
|
||||
* instead if the delta is small enough.
|
||||
*/
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"0x%x dropping sample buffer due delta=%d sample_cnt=%zu\n",
|
||||
ENDPOINT_NUMBER(endp), delta, state->sample_cnt);
|
||||
state->sample_cnt = 0;
|
||||
state->next_time = ts_no;
|
||||
} else if (delta < 0) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"RTP time jumps backwards, delta = %d, "
|
||||
"discarding buffered samples\n",
|
||||
delta);
|
||||
state->sample_cnt = 0;
|
||||
state->sample_offs = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Make sure the samples start without offset */
|
||||
if (state->sample_offs && state->sample_cnt)
|
||||
memmove(&state->samples[0],
|
||||
&state->samples[state->sample_offs],
|
||||
state->sample_cnt *
|
||||
sizeof(state->samples[0]));
|
||||
}
|
||||
|
||||
state->sample_offs = 0;
|
||||
|
||||
/* Append decoded audio to samples */
|
||||
decode_audio(state, &src, &nbytes);
|
||||
|
||||
if (nbytes > 0)
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Skipped audio frame in RTP packet: %zu octets\n",
|
||||
nbytes);
|
||||
} else
|
||||
ts_no = state->next_time;
|
||||
|
||||
if (state->sample_cnt < state->dst_packet_duration)
|
||||
return -EAGAIN;
|
||||
|
||||
max_samples =
|
||||
state->dst_packet_duration ?
|
||||
state->dst_packet_duration : state->sample_cnt;
|
||||
|
||||
nsamples = state->sample_cnt;
|
||||
|
||||
rc = encode_audio(state, dst, buf_size, max_samples);
|
||||
/*
|
||||
* There were no samples to encode?
|
||||
* TODO: how does this work for comfort noise?
|
||||
*/
|
||||
if (rc == 0)
|
||||
return -ENOMSG;
|
||||
/* Any other error during the encoding */
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
nsamples -= state->sample_cnt;
|
||||
|
||||
*len = rtp_hdr_size + rc;
|
||||
rtp_hdr->sequence = htons(state->next_seq);
|
||||
rtp_hdr->timestamp = htonl(ts_no);
|
||||
|
||||
state->next_seq += 1;
|
||||
state->next_time = ts_no + nsamples;
|
||||
|
||||
/*
|
||||
* XXX: At this point we should always have consumed
|
||||
* samples. So doing OSMO_ASSERT(nsamples > 0) and returning
|
||||
* rtp_hdr_size should be fine.
|
||||
*/
|
||||
return nsamples ? rtp_hdr_size : 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user