Compare commits

...

113 Commits

Author SHA1 Message Date
Max
9c0d105d09 ctrl: take both address and port from vty config
Change-Id: Id053bc02e0a6359e52a0f5e110128d3bb87ed151
2022-12-20 19:00:45 +03:00
Pau Espin Pedrol
ded02cfc29 iuup: Use osmo_amr_ft_valid() API
This is the only user outside libosmo-abis using this define, which
meaning is not clear at all. Let's simply use the related API to clearly
check the FT.

Related: SYS#6161
Change-Id: I40c7ed2e7f6a99a33b467734e33acf3d5befac0d
2022-12-19 13:24:23 +01:00
Pau Espin Pedrol
0cbed362cd osmux: Use new osmux_xfrm_input API to set name on each link
Depends: libosmo-netif.git Change-Id 8bb688e4827f345416c2a4526ced956a07fcc60b
Change-Id: Id5b7d497be4b3405403d30e40e1a52f13101cf5f
2022-11-21 10:52:17 +01:00
Pau Espin Pedrol
310e41cdf3 osmux: Rotate over available Osmux CID when allocating a new one
Before this patch, the free CID with the smallest number was always
selected to be used. This caused more or less the same subset of CIDs to
be used all the time, while the CIDs with bigger numbers were mostly
unused.
Let's distribute the use so that all CIDs are used roughly the same.
This has the advantage, among others, that the same CID will not be
re-used immediatelly after being freed if a new call is established.
It is useful to leave the CIDs unused for some time since the other end
peer may know of the call being tear down with some delay.
Hence if a new call is established immediately after the CID was
released, the same CID would be allocated and passed at the peer, which
would then detect that the old call (in its view still active) would
already make use of that remote CID.

Change-Id: I9dfbcc5e4b4c61ce217020e533d68fbcfa6b9f56
Related: SYS#6161
2022-11-15 18:10:28 +01:00
Max
a55bfdc436 Add realtime scheduling and set priority in service file
This sets lowest realtime priority which still takes precedence over any non-realtime service.

Related: OS#5687
Change-Id: Ib1705a164b04b876f129a17c4e8353b9ddcc538e
2022-11-14 10:52:06 +00:00
Harald Welte
6ea8d7dac6 Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
... if --enable-werror is used

Change-Id: Ib397f3ad748e17f20b6177ef706af65088571f70
2022-11-03 12:53:20 +01:00
Harald Welte
9befdeb673 Support building with -Werror=strict-prototypes / -Werror=old-style-definition
Unfortunately "-std=c99" is not sufficient to make gcc ignore code that
uses constructs of earlier C standards, which were abandoned in C99.

See https://lwn.net/ml/fedora-devel/Y1kvF35WozzGBpc8@redhat.com/ for
some related discussion.

Change-Id: I98a3c0d5cfda2c4b020652efb4f445f8288342b6
2022-11-03 12:53:20 +01:00
Neels Hofmeyr
5fb814b6b9 AMR->IuUP: log conversion, like for the flipside
For IuUP -> AMR, we log a message like
  Convert IuUP -> AMR OA:...
Do the same for the direction AMR -> IuUP.

Related: SYS#5092
Change-Id: I525685a7dedb6d5d1deecbd026844cbe23193fac
2022-10-28 19:04:00 +00:00
Pau Espin Pedrol
9ac9cb963d Improve logging on AMR OA<->BWE conversion failure
Change-Id: I7c7dd10650c1d249c723d6781585b343004bd64d
2022-10-26 12:36:48 +02:00
Pau Espin Pedrol
377d39122d osmux: Make sure RTP AMR feed to osmux is in octet-aligned mode
The Osmux implementation in libosmo-netif expects to work with RTP AMR
in octet-aligned mode. Therefore, if the peer connection received RTP
AMR in bandwidth-efficient mode, we need to convert it to octet-aligned
before feeding the packets to the osmux layer.

Related: SYS#6161
Change-Id: Ifeec44241079f7a31da12745c92bfdc4fb222f3a
2022-10-26 11:56:05 +02:00
Pau Espin Pedrol
d1e94c7ac3 osmux: Rename function and pass msgb directly to it
The new prefix now matches other related functions acting on an osmux
connection.
Pass the msgb to it so simplify new msgb copy.

Change-Id: I8c0121485d0c96f70fe8bcbdb150793d428183ff
2022-10-26 11:56:05 +02:00
Pau Espin Pedrol
6db3f7f1cb mgw: Rename s/mgcp_send_rtp/mgcp_conn_rtp_dispatch_rtp/
The previous name is misleading since the function is not really sending
stuff over a socket, but rather handling/dispatching the incoming
message internally (and finally later it may be sent over a socket under
some conditions).

Change-Id: Idaf791997b8438a4aede50f614afa0d55ad41faa
2022-10-26 11:55:26 +02:00
Pau Espin Pedrol
58c0b0a6f7 mgw: rx_rtp(): reorder checks and handlings
First validate the origin of the message, then later the content
of the message and finally execute whatever triggers are necessary.
This way contents from unknown senders are not even parsed or acted
upon, avoiding useless potential harm.

Change-Id: I011a6d7d705768c32a35cec5cd7169725a21a670
2022-10-25 18:23:09 +02:00
Pau Espin Pedrol
cca55247ed Rename and move func checking if amr mode is explicitly configured
The previous naming was quite confusing, since the function is not
really checking whether a conversion is needed, but rather whether the
codec has the AMR RTP mode defined explicitly and hence forced.

The previous naming didn't harm because the amr_oa_bwe_convert also
supports the conversion path OA<->OA and BE<->BE.
Hence nowadays the amr_oa_bwe_convert() function is called always if the
dst conn has its codec with AMR RTP mode explicitly set, no matter if
the src and dst conn have the same mode.

Related: SYS#6161
Change-Id: I8dce3038ebccf5e1e37e2908070a67d66693a96f
2022-10-25 18:23:08 +02:00
Pau Espin Pedrol
d266c374ee mgw: Log unexpected RTP AMR OA-vs-BE payload
Change-Id: Ib5ae82c01153398491b21191a8cec9969337bbbc
2022-10-25 18:23:04 +02:00
Pau Espin Pedrol
d358d71206 cosmetic: Clarify and fix typos in comment
Change-Id: Ibcbe7d85cf7e1912de73d59540f2dea1dfa5d98d
2022-10-25 13:09:36 +02:00
Neels Hofmeyr
5e6661eece IuUP->AMR: log whether converting to AMR OA or BE
Enhance the existing log message
  Convert IuUP -> AMR:...
to
  Convert IuUP -> AMR OA:...
(or BE) to show wether emitting Octet-Aligned or Bandwidth-Efficient.

Related: SYS#5092
Change-Id: I3672d01d2879ae8820176a46454f26a4f5f584de
2022-10-24 21:23:15 +02:00
Neels Hofmeyr
c1468ef7a5 IuUP->AMR: do not patch payload type a second time
When converting IuUP to AMR/RTP, bridge_iuup_to_rtp_peer() sets the AMR
side's payload type number and then calls mgcp_send(). In mgcp_send(),
do not attempt to patch the payload type number a second time.

In mgcp_send(), skip patching payload type numbers if the source side is
IuUP. This matches exactly the case of converting IuUP to AMR/RTP.

There already is a check for IuUP, but for the wrong side. Drop that one
and explain in a comment why.

Move the comment about transcoding into the failure branch, where it is
relevant and doesn't clutter the new explanation of payload type
patching conditions.

Related: OS#5720
Related: SYS#5092
Change-Id: I7c722cd959f76bd104ae4941d182c77e5c025867
2022-10-24 21:23:15 +02:00
Neels Hofmeyr
24763eaa73 AMR->IuUP: properly translate Q -> FQC
Fix the reversed logic when composing IuUP.FQC:
AMR.Q == 1 means the frame is good.

Without this fix, all frames on IuUP are marked as bad, and no voice is
heard on the IuUP side.

Related: SYS#5092
Change-Id: I29878dd27af9ba0c9e600324c528b22940cdcc30
2022-10-24 21:23:15 +02:00
Neels Hofmeyr
d8c2f31a87 AMR->IuUP: do not crash on AMR data before IuUP Init
When translating AMR to IuUP, when AMR data arrives before the IuUP side
has negotiated an IuUP Initialization, do not crash osmo-mgw, but return
failure and drop the AMR packet.

As soon as IuUP Initialization occured and RFCIs are defined, the AMR
starts to pass through to the IuUP side.

Related: SYS#5092
Change-Id: Id9efb7e523d8d9af988e4bf4f5e925839204f934
2022-10-24 21:23:02 +02:00
Pau Espin Pedrol
01b812ea76 mgcp_send: Use mgcp_conn_rtp_is_iuup() helper
Change-Id: I6988337f395168b88959876fe3827d8e67b8fc00
2022-10-19 19:18:50 +02:00
Pau Espin Pedrol
0807771b9e Fix misleading error log
The check is not for an AMR RTP packet. It actually only checks for RTP
header.

Change-Id: I60d7dbfeb2977bcb7102eed19e1c73c9433151a7
2022-10-19 19:06:47 +02:00
Pau Espin Pedrol
103e50a561 mgcp-client: Fix no 'mgw ' prefix written in old VTY node
Recent commit dropped the 'mgw ' prefix in commands under the "mgw" VTY
node because it was redundant.
However, for old apps still not supporting the 'mgw' node, the commands
are still printed in another node and hence the 'mgw ' prefix must still
be appeneded to them, to avoid breaking backward compatibility.

Related: SYS#5987
Fixes: 8c138fe89c
Change-Id: Ifbfb71f8864b425c1b842cdee241ce279d17a8ba
2022-10-19 17:22:48 +02:00
Pau Espin Pedrol
3a914e33e9 mgcp-client: Refactor system keeping old users not calling mgcp_client_pool_config_write() working
Move the regular writing logic to a subfunction, and raise the flag only
on one of them.
This simplifies the code paths but not marking stuff true and false over
the same code path.

Change-Id: I070798863f2bdc253df004a63262d4bcd529348f
2022-10-19 17:14:51 +02:00
Pau Espin Pedrol
2172f402a5 mgcp-client: Fix 'mgw endpoint-range' command dropped from old VTY node
That command was already deprecated when the new commands without the
"mgw" prefix were dropped, so there was no need to create a new command
for it (since it shouldn't be used and it's currently implemented as a
NOOP).

However, the recent patch moved the install line out of the common
function, which meant the command was not available anymore on the old
node, and as a result old config files using it would fail to be parsed.

This commit moves the command back to the common function so that it is
still available for config files using the old node.

Related: SYS#5987
Fixes: 8c138fe89c
Change-Id: I800abcc9869ed097a9d28715269c42552f5aaf29
2022-10-19 16:13:23 +02:00
Pau Espin Pedrol
8c138fe89c mgcp-client: Add new VTY commands under mgw node without mgw prefix
Previous existing ones are left marked as deprecated, to avoid breakage
with older configs.

Related: SYS#5987
Change-Id: Id55af13d2ecde49d968b9dca6a2f8108a17ec484
2022-10-19 12:47:33 +02:00
Pau Espin Pedrol
7881f7da0b mgcp-client: Introduce API mgcp_client_pool_config_write
It is not a good idea to use a personal write_config function for the
MGW node, since it's not meant to be a 1st level (top) node.
During write-config the node function will be called at an
implementation specific time (based on the order defined by the app in
the node type enum), so there's no real way to control that the output
of the MGW node will end up under the parent configured in
mgcp_client_pool_vty_init(). As mentioned the order can be tweaked based
on how the node enums are configured, installed, etc. but that's really
a nightmare, so let's better not rely on that.

Therefore, this patch introduces a new API which the users (apps such as
OsmoBSc and OsmoMSC) can use to write the config at the required time
(when writing its own parent node).
A hack is introduced internally to detect older versions of the users
which didn't call this function to still print stuff (up to to the app
if the order is correct).

Related: SYS#5987
Change-Id: I7a620cf47886d8ecab30ce369cf123d98ab842c5
2022-10-18 17:38:44 +02:00
Pau Espin Pedrol
d17a9de79e mgcp-client: Convert users supporting new MGW Pool VTY node during write-config
If the user (app) already supports the MGW Pool VTY command set
(mgcp_client_pool_vty_init() was called), then if single MGW mode is in
use it's because the config file was not updated to use the new MGW Pool
node. Let's convert it to the new format to help in transitioning to the
new VTY command set.

Related: SYS#5987
Change-Id: I2f6658cc66f8bcbd4a60ee2b932bb5dd65888233
2022-10-18 12:44:52 +02:00
Pau Espin Pedrol
8e74c63e15 mgcp-client: Use random free local port by default
Deprecate mgcp_client_connect2() and all the related messy system where
configured port is incremented until a free port is found.
Let's simply use local_port=0 by default and let the kernel take care of
doing all that.
The mgcp_client_connect2() is actually not being used anywhere outside
of libosmo-mgcp-client, so it's not a real problem deprecating it. We
could poitentially remove it too.

This helps in fixing a regression in recent refactoring commit
f48cd95bbc, which unified calls to
mgcp_client_connect() and in the process dropped the code path which was
setting the retry_n_ports=99.
As a result, since all libosmo-mgcp-client instances set local_port=2727
and addr=NULL by default, using MGW pooling or having several osmo-bsc
or osmo-msc processes would make creating the socket fail.

Change-Id: I5683bcf3b2c4e8058338433f2cd1b143753f6512
2022-10-17 19:22:41 +02:00
Pau Espin Pedrol
80dd576ad2 mgcp-client: vty: Write deprecation warning using non-mgw nodes
Let's advise all our users to migrate to the new pooled mode, the old
VTY interface should be dropped at some point to avoid making it
overcomplex to configure MGW. There's no need to maintain the same set
of commands under 2 different places.

Change-Id: I95f717a0fcd3c4ca622e3989baa28fac1f7ec1ca
2022-10-17 17:32:31 +02:00
Oliver Smith
cb922b646f mgcp_client_pool.h: add missing stdbool include
Fix for:
[   34s] In file included from vty.c:22:
[   34s] /usr/include/osmocom/mgcp_client/mgcp_client_pool.h:18:1: error: unknown type name 'bool'; did you mean '_Bool'?
[   34s]  bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);

Related: https://obs.osmocom.org/package/live_build_log/osmocom:master/osmo-bsc-nat/CentOS_8/x86_64
Change-Id: Ic3773f49160cbb8c6f53c4f0e17b897017dec98a
2022-10-14 16:42:03 +02:00
Pau Espin Pedrol
5d8b5b0935 mgcp-client: Introduce APIs to manually select mgcp_client from pool
This will be used by osmo-bsc to implement MGW-pinning for specific BTS.
This is useful for instance to keep all BTS connections targeting the
same MGW in order to make use of Osmux trunking optimizations (AMR
payload of different calls filling same underlaying UDP packet).

Related: SYS#5987
Change-Id: I75ce3e04cd3f6d9cc20d7b4fc0f51083780786c8
2022-10-13 18:47:07 +02:00
Pau Espin Pedrol
35bd2523e2 mgcp-client: Rearrange internal backpointers
Let's properly store backpointers so that it is easy to access all
relation chain (pool<->pool_member<->mgcp_client).

Related: SYS#5987
Change-Id: I5ec2465075da2e3c8eabca9df60681620a7db499
2022-10-13 18:42:34 +02:00
Pau Espin Pedrol
f45a9b9760 mgcp-client: Rearrange order of structs and APIs in header
Move mgcp_client_pool up in the file as a preparation for next commit,
where pool_member will have a pointer to the pool added.
The related APIs on the object are also moved up in the file.

Change-Id: I9ff9c6e1e722690835c5d59b1fa87fb7d9e3120c
2022-10-13 18:42:34 +02:00
Pau Espin Pedrol
f48cd95bbc mgcp-client: Refactor reinit of mgcp clients
The second parameter of mgcp_client_pool_member_reinit_client() will be
removed in a follow-up patch after further refactoring.

Related: SYS#5987
Change-Id: I0ab59278629c0e7e7c62a68b54b4235df58a5d77
2022-10-13 18:42:34 +02:00
Pau Espin Pedrol
7558c20973 mgcp-client: Move internal API acting on mgcp_client_pool to the correct file section
Change-Id: Ia0cccb783918eea72c4a77861dac4b60ad369b95
2022-10-13 18:42:31 +02:00
Pau Espin Pedrol
6ddc79b6ed mgcp-client: Create alloc() and free() internal APIs for mgcp_client_pool_member
Related: SYS#5987
Change-Id: Ibd2bf976885c777fe944652af6fe6eb0f1820468
2022-10-13 18:39:10 +02:00
Pau Espin Pedrol
ff5921573a mgcp-client: Move & rename helper function outside of vty code
This way acessing of the list is kept inside the same file.

Related: SYS#5987
Change-Id: I6b26c2de4064d9c28f92452178fff170fb295576
2022-10-13 18:38:57 +02:00
Pau Espin Pedrol
d4ad77d326 mgcp-client: Rename internal field in mgcp_client_pool
Having a list named pool inside an object already named pool is quite
confusing. Let's rename the field so that it makes sense immediatelly
when looking at it.

Change-Id: I4062af6b619317c48223ad4577eaaad05d4eec9d
2022-10-13 18:38:43 +02:00
Pau Espin Pedrol
a6917fecb1 mgcp-client: Fix typo in internal function name
Change-Id: I073038f1d6c68bc8546763a2c8c791fb5a021630
2022-10-13 18:38:43 +02:00
Pau Espin Pedrol
58877f04e3 mgcp-client: Avoid double iteration picking client from pool
Change-Id: I99e8be878452c5d8e2183239fbdd499dcf507e90
2022-10-13 18:38:43 +02:00
Pau Espin Pedrol
d4707e2185 mgcp-client: pool: Improve documentation of some internal fields
Change-Id: Ic9823ab0a3f101549452a7c7a0b1b5b21aaa837c
2022-10-13 18:38:28 +02:00
Pau Espin Pedrol
f633302c73 cosmetic: Fix typo in comment
Change-Id: I6b0fcd7ee13e0e712d47741258f83a6f98503e27
2022-10-13 13:20:10 +02:00
Pau Espin Pedrol
36413c011f osmux: Clean up mgcp_config osmux fields
* Move all of them to an anonymous "osmux" substruct to have them all
  together.
* Rename some fields to clarify its meanings, similar to what
  was already done in osmo-bts.
* Move the port VTY config next to the ip address ones.

Change-Id: Icc1c1ce3ab3a8beb941cda7c112485a0db882a90
2022-10-13 12:36:44 +02:00
Pau Espin Pedrol
833281dcb9 osmux: Introduce osmux peer-behind-nat (on|off) and rework conn activation
Change-Id: I7654ddf51d197a4107e55f4e406053b2e4a02f83
2022-10-12 17:13:04 +02:00
Pau Espin Pedrol
07bbd766c5 mgcp_conn_dump(): Separate dump for osmux and iuup connections
Change-Id: Iec1f2d61e4eb14a8a3c634e2642063bea6000c04
2022-10-06 18:49:31 +02:00
Pau Espin Pedrol
c7c8e649f1 osmux: Erase references to bsc-nat
Change-Id: I21ab7134de577278175132fc78431a249de76731
2022-10-06 18:24:24 +02:00
Pau Espin Pedrol
c0e1b1aec5 osmux: Move setting OSMUX_STATE_DISABLED to initializer function
Change-Id: I7c184b17075fc3e71f1f66775e16b56a5ae91b62
2022-10-06 16:21:37 +02:00
Pau Espin Pedrol
9735d21b9d osmux: Define osmux_dummy cfg as boolean
Change-Id: Ifc3384f9871ddfdbd6282c6e03bf6a2dd8a09a9e
2022-10-06 16:19:37 +02:00
Pau Espin Pedrol
705565d745 osmux: Make conn_osmux_{allocate,release}_local_cid() APIs static
They are used internally in the mgcp_osmux.c file.

Change-Id: If7c83f98a94818090173a8be9d3bff9818b2ead1
2022-10-06 14:37:33 +02:00
Pau Espin Pedrol
63088e0e61 osmux: Set conn->type during osmux_init_conn()
It's basically the same code path (one function calls the other), but it
makes a lot more sense to have it in the init function itself.

Change-Id: I63d7dfff451870f708f7cb710d66f4ec786c27d7
2022-10-06 14:33:00 +02:00
Pau Espin Pedrol
887c93e198 osmux: Simplify and constify param passing
Parameters passed to several functions are rearrange to make code
simplier to follow, as well as dependencies between the different
functions. As a result, some parameters can be marked as const while
doing the change.

Change-Id: Idebd4a66630c16548f557632a54d6b7e1b3906fd
2022-10-06 14:20:52 +02:00
Pau Espin Pedrol
2ca48823b1 Check once if remote addr is available when sending dummy packet
It's checked in all code paths being called, which makes sense since
it's impossible to send anything if the remote address is not set. Let's
check it once in a unique to simplify the code.

Change-Id: I224dbfeda17c364b85166268e2ac1e019a87edb6
2022-10-06 13:10:51 +02:00
Pau Espin Pedrol
e7de137b29 osmux: cosmetic: Fix indentation
Change-Id: Ic7087e7907c1078d134d7d9b11ed6a6bf1941308
2022-10-06 13:10:51 +02:00
Pau Espin Pedrol
c1ad7fd92b osmux: Drop unused role parameter
Change-Id: I39c2852bb60aaba4f85188c55f157e4abec47a0e
2022-10-06 13:10:51 +02:00
Pau Espin Pedrol
3779919551 osmux: Add square brackets around IPv6 address to distinguish port in log line
Change-Id: I811ac5b4386f06c224f29f44f10dce4008fa7a4f
2022-10-06 13:10:41 +02:00
Pau Espin Pedrol
8e0d101997 osmux: Change couple log lines to OSMUX category
Change-Id: Ia04d08099f0b1e81707699d872779108f22522bf
2022-10-06 10:31:19 +02:00
Pau Espin Pedrol
654b68d602 Clean up local var pointers in mgcp_get_local_addr()
Change-Id: I12f1d38b70f97426318e948cd80f9efc2592d54b
2022-10-05 10:37:49 +02:00
Pau Espin Pedrol
70c03f5e44 Add Osmux IPv6 support
A new osmux bind-ip-v6 VTY command is added, similar to what's already
available for RTP. This way the user can decide whether to support IPv4,
IPv6 or both types of IP versions.

Both IP sockets are by default disabled, and must be explicitly enabled
by setting the bind-ip in the VTY configuration.

Change-Id: I446cd7da217e9f4a74995d7784ae55dcc60a29b7
2022-10-05 10:32:42 +02:00
Pau Espin Pedrol
e56ec4a146 osmux: Use available API to check if remote end is known
Since recently the port is guaranteed to be placed at
CRCX/MDCX in the sockaddr, hence we can check it using the API instead
of checking manually only for the address part.

In osmux_send_dummy() we actually fix a bug where an in_addr was being
compared against a struct sockaddr.

Change-Id: I736e7f4c51e577d8eb0b96bc776f984f928b6d27
2022-10-04 14:44:48 +02:00
Pau Espin Pedrol
5ffd127384 Get rid of separate rtp_port field
Let's use the port part of the struct mgcp_rtp_end->addr field instead
of keeping it separate. This makes it easier passing around and
using/checking the RTP remote address + port, and avoids confusion
having to check stuff outside of the address, with its port part
potentially unset.

Change-Id: I294eb5d85fae79bf62d36eb9e818426e187d442c
2022-10-04 14:44:44 +02:00
Pau Espin Pedrol
051eb4d563 Use new libosmocore API osmo_sockaddr_is_any()
Depends: libosmocore.git Change-Id I2810a889fc14052d0e0be6a2b500ad4e5088ffa9
Change-Id: Ib2ba708bdc834359de8a7cce302e2dc1f8c64954
2022-10-04 12:51:15 +02:00
Pau Espin Pedrol
e740665cab Fix regression in detection of legacy dummy packets
A commit refactored this code around one year ago, which broke osmux
detection of dummy messages. This commit partially reverts the earlier
commit and rearranges the existing code to make it more robust.

Fixes: b3d14eb552
Change-Id: Iedf085932c45af5d13e04e56a4cd1082de81d869
2022-10-04 12:16:15 +02:00
Pau Espin Pedrol
abb9d47c90 send_dummy: Use proper condition to test if conn is osmux
Change-Id: I493e7afaf8e6edb5bf975b3097fab49986d064cf
2022-10-04 12:10:10 +02:00
Pau Espin Pedrol
2dd2b33030 osmux: Log remote address upon rx of osmux pkt
Change-Id: Ie2a375711c7c0989161ae651ea6f0695799e2670
2022-10-03 18:10:55 +02:00
Pau Espin Pedrol
69f15e4e95 osmux: Fill in from_addr in struct osmo_rtp_msg_ctx
Change-Id: I9783978e295b964ca914f8d90d73effa8785f10d
2022-10-03 18:04:07 +02:00
Pau Espin Pedrol
b0ea7976bf osmux: Match remote address in osmux_conn_lookup()
Depends: libosmo-netif.git I95433b18802f73fa70e758f4aa02128eee940d88
Change-Id: Ia717efa5f68e9412b86ef44a4c42a0715ff0e469
2022-10-03 18:04:03 +02:00
Pau Espin Pedrol
9d939b6d5d osmux: Unify rtp_conn osmux type into a single type
There's no need to separate between BSS and CN side nowadays, the
different types are used nowehere. This separation dates from
osmo-bsc-nat code days.

Change-Id: I65effeddf033eb1955553e8d659c593b4e67f7bc
2022-10-03 17:16:16 +02:00
Pau Espin Pedrol
de805b6772 osmux: cleanup misleading code calling rtp_bridge_cb
Documentation of rtp_bridge_cb was outdated, and caused confusion when
adding initial osmux support. Let's clear all the mess.

Change-Id: I42d1f2e2919eae3b1555ca4929e571855960792e
2022-10-03 17:16:16 +02:00
Pau Espin Pedrol
cb25a0aa48 osmux: Drop logging of osmux internal counters
This way we have no more access to internal osmux structures.
Moreover, we already have similar information in our rate_ctrs, so
there's no need to print those there.

Change-Id: I853e118f843070ea29b19e1b0fe56b52f267437a
2022-10-03 15:57:09 +02:00
Pau Espin Pedrol
72eff2cf6a Allocate struct osmux_in_handle through new libosmo-netif APIs
Change-Id: I013c99d1f915279684ce278648e9c69e39b94266
Depends: libosmo-netif.git I752ab031f935f04731bb1a354333f1682a1aa5bd
2022-10-03 15:57:09 +02:00
Pau Espin Pedrol
1c5fcb0791 osmux: Keep decoding osmux pkt if a batch contains an unknown CID
Receiving an unknown CID (for which we don't have an active conn) is
totally expected at the end of the call, were some messages from the
peer may be send for a while, specially if latency is high.
If this occurs, we simply drop that batch and keep decoding the osmux
message in order to keep delivering content to other circuits.

Related: SYS#5987
Change-Id: I315949853bdcc07bef15d2e8579029cc72c427cf
2022-09-29 16:02:10 +02:00
Pau Espin Pedrol
48fb176fbc osmux: Lower log level when osmux batch received for unknown CID
This is actually quite common, since our peer may be sending some osmux
packets to us a while after we have closed the conn on our side,
specially if latency is high in the network (eg satellite links).

Related: SYS#5987
Change-Id: Idffd91b68d1f98ac906d78e7fbc0e6eaa1962f9e
2022-09-29 16:02:03 +02:00
Pau Espin Pedrol
4d090d85f4 osmux: Drop unneeded comment block
Change-Id: Iae04a7c4b496492ce5b363a56fdd871b210012ed
2022-09-29 16:02:03 +02:00
Pau Espin Pedrol
81c5847434 cosmetic: osmux: Drop extra empty line
Change-Id: I679a62c49290dfeb9e2c63890daa67002bfe3339
2022-09-27 13:45:07 +02:00
Pau Espin Pedrol
d48a811f6c osmux: Allocate rate counters during initialization of osmux conn
Let's not delay allocation of rate counters until the osmux conn is
fully enabled, since we may want to count stuff before that point in
time.

Fixes crash accessing null conn->osmux.ctrg in
MGCP_Test.TC_two_crcx_and_rtp_osmux_bidir.

Change-Id: Ic31d3567f4d24e628f8983d8362e5c7c2f66ec02
2022-09-27 13:45:04 +02:00
Pau Espin Pedrol
b7f52b414e osmux: Rename field s/init/initialized
Change-Id: Ic48de396b1d8a0774611b4a1c2248ba79bdaf044
2022-09-25 00:14:03 +02:00
Pau Espin Pedrol
ea7aaf2eca vty: show per-connection Osmux VTY stats
Related: SYS#5987
Change-Id: Ieab6dcbd195c8e01a73a2a832bce78ee015ae1c3
2022-09-25 00:06:00 +02:00
Pau Espin Pedrol
432ee9d150 osmux: Improve per-conn tx rate counters
Change-Id: If030f5d921bdfcfcd00b015b4a9e48bb3b04e721
2022-09-25 00:06:00 +02:00
Pau Espin Pedrol
b4a59475d2 osmux: Fix incorrect rate_ctr_group used in mgcp_osmux.c
During development of the counters, they were first added to the same
RTP counter group and later on split, but some places still used the
RTP related functions to increment the counters.
Let's add a seaprate set of helpers to update the correct osmux counter
group.

Fixes: 582c2bf7b0

Change-Id: Ia2e5601c7d476b79afd95032dbc019517f8209af
2022-09-25 00:05:49 +02:00
Pau Espin Pedrol
2177919edb osmux: Support local CID != remote CID
So far the implementation only allowed the remote CID being the same as
the one dynamically implemented internally.

Related: SYS#6138
Change-Id: I6b03eabc0305580c9788c529bec7dda9044a008f
2022-09-23 16:55:46 +02:00
Pau Espin Pedrol
87f114a1d0 Use bool type instead of int in config field
Change-Id: Ie2624a6a6848c3c88deb39760317860d8074acb9
2022-09-23 15:48:43 +02:00
Pau Espin Pedrol
928a20b540 osmux: Rename field osmux usage policy and define it with proper type
Change-Id: I7f41a443f488b75df792597ec3cec8f7e97a7411
2022-09-23 15:48:20 +02:00
Pau Espin Pedrol
b9022497d8 cosmetic: osmux: Fix formatting of if-else brackets
Change-Id: I748d41cd110841ef121f70560e70c07de56aa9da
2022-09-22 21:47:23 +02:00
Pau Espin Pedrol
582c2bf7b0 osmux: Add connection and global rate counters
Change-Id: I200a4aa3908cac0ec729d980a66f3df7f55e4da7
2022-09-22 21:44:46 +02:00
Pau Espin Pedrol
663ba5c41f Use 'static const' instead of 'const static' everywhere
As requested by the linter on a new patch being submitted.

Change-Id: I692624da6a1c7f59ac2989509f074cb52d089907
2022-09-22 21:43:45 +02:00
Pau Espin Pedrol
daf5bcea99 mgcp_conn: rename field s/rate_ctr_group/ctrg/g
This makes all lines operating on rate groups way shorter. The "ctrg"
naming is already used in tons of places in osmocom code.

Change-Id: I745eddbf66e7d811bb73c8ae9bb54ea93073c71b
2022-09-22 21:21:12 +02:00
Pau Espin Pedrol
a29f155301 Fix typo in ratectr description
Change-Id: I2ac8581f13814f320767ba188ef7cf3286fa443d
2022-09-22 21:21:12 +02:00
Pau Espin Pedrol
941e317c97 osmux: Get rid of static NULL talloc context
struct osmux_handle, which is shared by several rtp_conn, is
attached to the trunk object, since the socket also attaches to it.

Related: SYS#5987
Change-Id: If4980424cdb8e3dc26a23e9ee419c0a38912f38f
2022-09-22 21:21:11 +02:00
Pau Espin Pedrol
3fbf035923 osmux: Clean up helper macro osmux_chunk_length()
Change-Id: I482d8c5be08610788c2ed98e3b87ae4184075e8d
2022-09-22 19:01:33 +02:00
Pau Espin Pedrol
21bcf6abd8 osmux: Attach osmux to virtual trunk
It makes sense to handle one osmux socket per trunk. Since we only so
far operate one RTP/osmux trunk, let's stick to that only one for
simplicity.

Change-Id: I173266c4058d5db9479d773d7dec1304bc8f1f99
2022-09-22 18:23:05 +02:00
Pau Espin Pedrol
26e810d8a9 cosmetic: mgcp_conn.h: fix indentation whitespace
Change-Id: I6b12b589d1b0a8f95a8283aac8ba0ad22026b43f
2022-09-22 17:16:20 +02:00
Pau Espin Pedrol
4d1a52d463 osmux: Log sendto() error
Change-Id: Icd91b725ac6b5ef2b9307cc99d67d60efdfa32cb
2022-09-22 17:11:57 +02:00
Pau Espin Pedrol
83df47cd7a cosmetic: vty: Fix indentation whitespace
Change-Id: I2f42707f815ca58690d86a956118b6661c59fda3
2022-09-21 20:07:59 +02:00
Pau Espin Pedrol
c5bbb78ffe osmux: set log level of expected code path to INFO
Change-Id: I5caf850b7bb19c66716139512f16568d4f8459eb
2022-09-19 16:46:02 +02:00
Harald Welte
e0e5a772f4 Make osmo_mgcpc_ep_fsm_pre_term() static
This is a call-back for FSM pre-termination and it should not
be publicly exported.

Change-Id: Iaa44906baa201571f6bc3192bd3caacb272fec0b
2022-09-16 10:37:22 +00:00
Pau Espin Pedrol
e39ae87ea3 osmux: don't store conn ptr inside shared osmux_handle
The struct osmux_handle is a shared structure which goes together 1-1
with libosmo-netif's struct osmux_in_handle, which is common to all CIDs
to be muxed together. Hence, it makes no sense to store a specific conn
object to it, since it actually manages several of them. Hence, all the
conn specific stuff must be handled beforehand, not at osmux deliver
time.

Related: SYS#5987
Change-Id: Ie739b556e9eb7d3133e798831a09728c7cc87135
2022-09-09 18:13:45 +02:00
Pau Espin Pedrol
8b0a614e43 osmux: Fix memleak on error code path
Change-Id: Ib84f78a53293799b925b645156513e129c32c705
2022-09-09 18:13:45 +02:00
Pau Espin Pedrol
c61664c2b2 osmux: Log refcounting of osmux_handle_list
Change-Id: Ia873e3021078976748762baaf406865149b2a090
2022-09-09 18:13:45 +02:00
Pau Espin Pedrol
15e7e4f37d osmux: Use osmo_sockaddr wherever possible
This cleans up all the code, and makes it a lot easier to add IPv6 support
later on (mostly only a matter of adding an IPv6 bind address in VTY).
Similar changes were done to the Osmux code being added to osmo-bts.

Related: SYS#5987
Change-Id: I5a100fc654f88d29b2bcd85889a5a92aef3d576d
2022-09-09 18:13:40 +02:00
Pau Espin Pedrol
ab8371c6d7 osmux: Use better name for function which may allocate a new struct
Change-Id: I867e3f74775d97749a78c2f198452b1f2916492f
2022-09-09 16:40:57 +02:00
Pau Espin Pedrol
8c777990a5 cosmetic: main: Properly format log_info_cat
Change-Id: If130d1debc1977b7f8d82f515861df2c513d55bb
2022-09-09 16:21:22 +02:00
Pau Espin Pedrol
ec5e85b84e Add Osmux log category
Change-Id: Ia75de7965c39f3f84164a25584d901dbdd43f10f
2022-09-09 16:04:19 +02:00
Pau Espin Pedrol
ab4e8663e1 mgw: Use X-Osmux string define
Change-Id: Ib437c0a6b414f1d8f08fdb90e88a61e9aed2780d
2022-09-08 15:15:37 +02:00
Pau Espin Pedrol
a4f783b51b cosmetic: osmux: Fix wrong indentation
Change-Id: I7675d17bb3fc827e05c197104be29eadd8ddf3f2
2022-09-07 20:04:20 +02:00
Pau Espin Pedrol
479cf76e55 mgw: Fix osmux conn local IP selection
The local Osmux IP address (cfg->osmux_addr) was never applied in
generated MGCP messages. Instead, the RTP one was written into the
MGCP message.

Related: SYS#5987
Change-Id: I305f2501221e86d1eb0140446c03f36698f3194a
2022-09-07 19:42:59 +02:00
Pau Espin Pedrol
33639166a2 osmux: Use new osmux APIs to let libosmo-netif alloc struct osmux_out_handle
This way we don't need to worry about implementation details (struct
size) in the future in case they change (they will).

Related: OS#5987
Requires: libosmo-netif.git Change-Id Ie8df581f375c9a183a7af60b431561bda82f6e34
Change-Id: I2d0d8c152b8f1234ddfcd74d6cb04b1818b41510
2022-09-07 08:29:35 +00:00
Max
709aad28ed Set working directory in systemd service file
By default systemd will execute service with root directory (or home directory for user instance) which might result in
attempts to create files in unexpected place. Let's set it to 'osmocom' subdir of state directory (/var/lib for system instance) instead.

Related: OS#4821
Change-Id: I7696cd92953787591e7b4777ee79c2671326b972
2022-08-30 19:45:32 +07:00
Pau Espin Pedrol
5892b2e4db Use Osmux default port define from libosmo-netif
Change-Id: Ibf5fbec591307232be98cad914c0df4b2993db15
Requires: libosmo-netif.git Ibfd058bceeeaa1384a00d8fcd6d6268b445e19bd
2022-08-12 14:08:34 +02:00
Pau Espin Pedrol
f1f73b8e1d mgcp_osmux: Drop duplicated conn_osmux_release_cid() in code path
Change-Id: I65d9978ee93ef9b1a2e48a92617ae8de3e131a93
2022-08-12 14:06:50 +02:00
Philipp Maier
0fdc08c551 mgcp_e1: fix apidoc
Change-Id: Iaccb9b67e72d113483160e61f660ea9c4c2f53a5
2022-08-10 14:13:41 +02:00
Vadim Yanitskiy
5be57da075 libosmo-mgcp-client: add -no-undefined to *_la_LDFLAGS
Make sure that there is no undefined references in shared libraries.

Change-Id: If6aa8016026beb8bad735987f3ab6e0d114b86a5
2022-08-04 05:35:43 +07:00
Pau Espin Pedrol
147184eb06 mgcp-client: Remove impossible code path
read(4096 - 128) cannot return > 4096 - 128.

Change-Id: I352c3b28c8de6482277cb84cd0f51893494dc929
2022-06-29 18:45:02 +02:00
40 changed files with 1389 additions and 967 deletions

View File

@@ -24,3 +24,6 @@
# If any interfaces have been removed or changed since the last public release, a=0.
#
#library what description / commit summary line
libosmo-netif >1.2.0 OSMUX_DEFAULT_PORT, osmux_xfrm_output_*, osmux_xfrm_input_*
libosmocore >1.7.0 osmo_sockaddr_is_any()
libmgcp-client NEW APIs mgcp_client_pool_member_...(), mgcp_client_pool_config_write()

View File

@@ -79,6 +79,7 @@ AC_ARG_ENABLE(werror,
if test x"$werror" = x"yes"
then
WERROR_FLAGS="-Werror"
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
CFLAGS="$CFLAGS $WERROR_FLAGS"

View File

@@ -3,9 +3,16 @@ Description=Osmocom Media Gateway (MGW)
[Service]
Type=simple
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
Restart=always
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
RestartSec=2
# CPU scheduling policy:
CPUSchedulingPolicy=rr
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
CPUSchedulingPriority=1
# See sched(7) for further details on real-time policies and priorities
[Install]
WantedBy=multi-user.target

View File

@@ -6,7 +6,6 @@ noinst_HEADERS = \
mgcp_endp.h \
mgcp_sdp.h \
mgcp_codec.h \
mgcp_ctrl.h \
mgcp_trunk.h \
debug.h \
mgcp_ratectr.h \

View File

@@ -30,6 +30,7 @@
enum {
DRTP,
DE1,
DOSMUX,
Debug_LastEntry,
};

View File

@@ -29,6 +29,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/osmux.h>
#include <arpa/inet.h>
#include <sys/types.h>
@@ -156,24 +157,26 @@ struct mgcp_config {
enum mgcp_role role;
/* osmux translator: 0 means disabled, 1 means enabled */
int osmux;
/* addr to bind the server to */
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.
*/
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;
struct {
/* Osmux usage policy: */
enum osmux_usage usage;
/* addr to bind the server to */
char *local_addr_v4;
char *local_addr_v6;
/* osmux port */
uint16_t local_port;
/* The osmux socket is allocated on demand (1st time used).
* This tells us if the osmux socket is already initialized. */
bool initialized;
/* osmux batch factor: from 1 to 4 maximum */
int batch_factor;
/* osmux batch size (in bytes) */
int batch_size;
/* Pad circuit with dummy AMR frames if no payload to transmit is available */
bool dummy_padding;
/* Whether peer is behind NAT (Retrieve remote addr from 1st received Osmux packet) */
bool peer_behind_nat;
} osmux;
/* domain name of the media gateway */
char domain[255+1];
@@ -207,4 +210,4 @@ int mgcp_send_reset_all(struct mgcp_config *cfg);
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio);
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);

View File

@@ -17,4 +17,5 @@ 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);
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);

View File

@@ -46,8 +46,7 @@ LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
/* 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,
MGCP_RTP_OSMUX,
MGCP_RTP_IUUP,
};
@@ -80,19 +79,20 @@ struct mgcp_conn_rtp {
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 */
/* Is local_cid holding valid data? is it allocated from pool? */
bool local_cid_allocated;
/* Allocated local Osmux circuit ID for this conn */
uint8_t local_cid;
/* Is remote_cid holding valid data? was it already received from client? */
bool remote_cid_present;
/* Received remote Osmux circuit ID for this conn */
uint8_t remote_cid;
/* handle to batch messages, shared (refcounted) among several conns */
struct osmux_in_handle *in;
/* handle to unbatch messages */
struct osmux_out_handle out;
/* statistics */
struct {
uint32_t chunks;
uint32_t octets;
} stats;
/* handle to unbatch messages, one allocated and owned per conn */
struct osmux_out_handle *out;
/* statistics: */
struct rate_ctr_group *ctrg;
} osmux;
struct {
@@ -103,7 +103,7 @@ struct mgcp_conn_rtp {
struct osmo_iuup_rnl_prim *init_ind;
} iuup;
struct rate_ctr_group *rate_ctr_group;
struct rate_ctr_group *ctrg;
};
/*! MGCP connection (untyped) */
@@ -145,12 +145,12 @@ struct mgcp_conn {
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_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
@@ -163,7 +163,7 @@ static const struct rate_ctr_desc mgcp_conn_rate_ctr_desc[] = {
[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."}
[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "Dropped rtp packets."}
};
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
@@ -181,9 +181,49 @@ static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
};
/* Osmux connection related counters */
enum {
OSMUX_CHUNKS_RX_CTR,
OSMUX_OCTETS_RX_CTR,
OSMUX_RTP_PACKETS_TX_CTR,
OSMUX_RTP_PACKETS_TX_DROPPED_CTR,
OSMUX_AMR_OCTETS_TX_CTR,
/* Only available in global stats: */
OSMUX_NUM_CONNECTIONS,
OSMUX_PACKETS_RX_CTR,
OSMUX_PACKETS_TX_CTR,
OSMUX_DROPPED_PACKETS_CTR,
};
/* RTP per-connection statistics. Instances of the corresponding rate counter group
* exist for the lifetime of an RTP connection.
* Must be kept in sync with all_rtp_conn_rate_ctr_desc below */
static const struct rate_ctr_desc mgcp_conn_osmux_rate_ctr_desc[] = {
[OSMUX_CHUNKS_RX_CTR] = {"osmux:chunks_rx", "Inbound Osmux chunks."},
[OSMUX_OCTETS_RX_CTR] = {"osmux:octets_rx", "Inbound Osmux octets."},
[OSMUX_RTP_PACKETS_TX_CTR] = {"osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
[OSMUX_AMR_OCTETS_TX_CTR] = {"osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
};
/* Aggregated Osmux connection stats. These are updated when an Osmux connection is freed.
* Must be kept in sync with mgcp_conn_osmux_rate_ctr_desc above */
static const struct rate_ctr_desc all_osmux_conn_rate_ctr_desc[] = {
[OSMUX_CHUNKS_RX_CTR] = {"all_osmux:chunks_rx", "Inbound Osmux chunks."},
[OSMUX_OCTETS_RX_CTR] = {"all_osmux:octets_rx", "Inbound Osmux octets."},
[OSMUX_RTP_PACKETS_TX_CTR] = {"all_osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"all_osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
[OSMUX_AMR_OCTETS_TX_CTR] = {"all_osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
/* These last counters below do not exist in per-connection stats, only here: */
[OSMUX_NUM_CONNECTIONS] = {"all_osmux:num_closed_conns", "Total number of osmux connections closed."},
[OSMUX_PACKETS_RX_CTR] = {"all_osmux:packets_rx", "Total inbound UDP/Osmux packets."},
[OSMUX_PACKETS_TX_CTR] = {"all_osmux:packets_tx", "Total outbound UDP/Osmux packets."},
[OSMUX_DROPPED_PACKETS_CTR] = {"all_osmux:dropped_packets", "Dropped outbound UDP/Osmux packets."}
};
/* Was conn configured to handle Osmux? */
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
return conn->type == MGCP_RTP_OSMUX;
}
/* Was conn configured to handle Osmux? */

View File

@@ -1,24 +0,0 @@
/*
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
const char *bind_addr, uint16_t port);

View File

@@ -40,8 +40,13 @@ LOGP(cat, level, "endpoint:%s " fmt, \
endp ? endp->name : "none", \
## args)
enum rtp_proto {
MGCP_PROTO_RTP,
MGCP_PROTO_RTCP,
};
struct osmo_rtp_msg_ctx {
int proto;
enum rtp_proto proto;
struct mgcp_conn_rtp *conn_src;
struct osmo_sockaddr *from_addr;
};

View File

@@ -9,7 +9,8 @@
/* The following constant defines an RTP dummy payload that is used for
* "UDP Hole Punching" (NAT) */
static const char rtp_dummy_payload[] = { 0x23 };
#define MGCP_DUMMY_LOAD 0x23
static const char rtp_dummy_payload[] = { MGCP_DUMMY_LOAD };
/* Check if the data in a given message buffer matches the rtp dummy payload
* defined above */
@@ -92,7 +93,7 @@ struct mgcp_rtp_end {
struct osmo_sockaddr addr;
/* in network byte order */
int rtp_port, rtcp_port;
int rtcp_port;
/* currently selected audio codec */
struct mgcp_rtp_codec *codec;
@@ -156,7 +157,7 @@ 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);
int 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,
@@ -178,5 +179,9 @@ void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_stat
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id, int inc);
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id);
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
uint32_t mgcp_get_current_ts(unsigned codec_rate);
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);

View File

@@ -80,6 +80,8 @@ struct mgcp_ratectr_trunk {
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 aggregates stats of individual Osmux connections. */
struct rate_ctr_group *all_osmux_conn_stats;
/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
struct rate_ctr_group *e1_stats;
};

View File

@@ -1,25 +1,22 @@
#pragma once
#include <stdint.h>
#include <osmocom/core/socket.h>
#include <osmocom/netif/osmux.h>
struct mgcp_conn_rtp;
struct mgcp_trunk;
struct mgcp_endpoint;
struct mgcp_conn_rtp;
#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_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
struct osmo_sockaddr *addr, uint16_t port);
int osmux_init(struct mgcp_trunk *trunk);
int osmux_init_conn(struct mgcp_conn_rtp *conn);
int conn_osmux_enable(struct mgcp_conn_rtp *conn);
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
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 conn_osmux_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn);
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg);
int osmux_send_dummy(struct mgcp_conn_rtp *conn);
void osmux_cid_pool_get(uint8_t osmux_cid);
int osmux_cid_pool_get_next(void);
@@ -29,10 +26,14 @@ int osmux_cid_pool_count_used(void);
enum osmux_state {
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 */
OSMUX_STATE_ACTIVATING, /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref conn_osmux_enable. */
OSMUX_STATE_ENABLED, /* Osmux was initialized by \ref conn_osmux_enable and can process frames */
};
extern const struct value_string osmux_state_strs[];
static inline const char *osmux_state_str(enum osmux_state val)
{ return get_value_string(osmux_state_strs, val); }
enum osmux_usage {
OSMUX_USAGE_OFF = 0,
OSMUX_USAGE_ON = 1,

View File

@@ -7,7 +7,7 @@
/* 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_LOCAL_PORT_DEFAULT 0
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
@@ -140,7 +140,7 @@ 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);
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports) OSMO_DEPRECATED("Use mgcp_client_connect() instead");
void mgcp_client_disconnect(struct mgcp_client *mgcp);
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);

View File

@@ -16,7 +16,7 @@ struct mgcp_client {
mgcp_trans_id_t next_trans_id;
struct llist_head responses_pending;
struct llist_head inuse_endpoints;
struct mgcp_client_pool *pool;
struct mgcp_client_pool_member *pool_member;
};
struct mgcp_inuse_endpoint {

View File

@@ -1,11 +1,21 @@
#pragma once
#include <stdbool.h>
struct mgcp_client;
struct mgcp_client_pool;
struct mgcp_client_pool_member;
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr);
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member);
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);

View File

@@ -1,9 +1,31 @@
#pragma once
/* Struct to handle a pool of MGWs. (Use _pool functions) */
struct mgcp_client_pool {
/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
* mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
struct mgcp_client *mgcp_client_single;
/* A list that manages the pool members (see mgcp_client_pool_member->list above) */
struct llist_head member_list;
/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
* mgcp_client_pool_vty_init() */
char *vty_indent;
/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
struct cmd_node *vty_node;
};
/* Struct to handle a member of a pool of MGWs. */
struct mgcp_client_pool_member {
/* Entry in llist mgcp_client_pool->pool. */
struct llist_head list;
/* The pool managing this object: */
struct mgcp_client_pool *pool;
/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
* the log. */
unsigned int nr;
@@ -24,22 +46,7 @@ struct mgcp_client_pool_member {
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;
};
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr);
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member);
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member);
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);

View File

@@ -35,4 +35,8 @@ libosmo_mgcp_client_la_SOURCES = \
mgcp_client_pool.c \
$(NULL)
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
libosmo_mgcp_client_la_LDFLAGS = \
$(AM_LDFLAGS) \
-version-info $(MGCP_CLIENT_LIBVERSION) \
-no-undefined \
$(NULL)

View File

@@ -442,7 +442,7 @@ static int mgcp_parse_osmux_cid(const char *line)
osmux_cid, OSMUX_CID_MAX);
return -2;
}
LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
LOGP(DLMGCP, LOGL_DEBUG, "MGW offered Osmux CID %u\n", osmux_cid);
return osmux_cid;
}
@@ -726,10 +726,6 @@ static int mgcp_do_read(struct osmo_fd *fd)
msgb_free(msg);
return -1;
} else if (ret > 4096 - 128) {
LOGPMGW(mgcp, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
msgb_free(msg);
return -1;
}
msg->l2h = msgb_put(msg, ret);
@@ -773,7 +769,7 @@ struct mgcp_client *mgcp_client_init(void *ctx,
mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
mgcp->actual.local_port = conf->local_port > 0 ? (uint16_t)conf->local_port :
MGCP_CLIENT_LOCAL_PORT_DEFAULT;
mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
@@ -803,49 +799,6 @@ struct mgcp_client *mgcp_client_init(void *ctx,
return mgcp;
}
static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)
{
int rc;
struct osmo_wqueue *wq;
unsigned int i;
wq = &mgcp->wq;
for (i = 0; i < retry_n_ports + 1; i++) {
/* Initialize socket with the currently configured port number */
rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rc > 0)
return rc;
/* If there is a different port than the default port configured then we assume that the user has
* chosen that port conciously and we will not try to resolve this by silently choosing a different
* port. */
if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)
return -EINVAL;
if (i == retry_n_ports) {
/* Last try failed */
LOGPMGW(mgcp, LOGL_NOTICE, "Failed to bind to %s:%d -- check configuration!\n",
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port);
if (retry_n_ports == 0)
return -EINVAL;
} else {
/* Choose a new port number to try next */
LOGPMGW(mgcp, LOGL_NOTICE,
"Failed to bind to %s:%d, retrying with port %d -- check configuration!\n",
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
mgcp->actual.local_port + 1);
mgcp->actual.local_port++;
}
}
LOGPMGW(mgcp, LOGL_FATAL, "Failed to find a port to bind on %u times -- check configuration!\n", i);
return -EINVAL;
}
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
@@ -882,9 +835,8 @@ static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgc
/*! Initialize client connection (opens socket)
* \param[in,out] mgcp MGCP client descriptor.
* \param[in] retry_n_ports number of consecutive local ports that should be used to retry on failure.
* \returns 0 on success, -EINVAL on error. */
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
int mgcp_client_connect(struct mgcp_client *mgcp)
{
struct osmo_wqueue *wq;
int rc;
@@ -903,7 +855,9 @@ int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
rc = init_socket(mgcp, retry_n_ports);
rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rc < 0) {
LOGPMGW(mgcp, LOGL_FATAL,
"Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
@@ -929,12 +883,12 @@ error_close_fd:
return rc;
}
/*! Initialize client connection (opens socket)
/*! DEPRECATED: Initialize client connection (opens socket)
* \param[in,out] mgcp MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
int mgcp_client_connect(struct mgcp_client *mgcp)
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
{
return mgcp_client_connect2(mgcp, 99);
return mgcp_client_connect(mgcp);
}
/*! Terminate client connection

View File

@@ -227,7 +227,7 @@ static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
static void fill_event_names()
static void fill_event_names(void)
{
int i;
for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
@@ -243,7 +243,7 @@ static void fill_event_names()
}
}
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
fill_event_names();
@@ -997,7 +997,7 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
return 0;
}
void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
static void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
{
int i;
struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);

View File

@@ -760,7 +760,7 @@ const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
return buf;
}
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
}

View File

@@ -18,6 +18,7 @@
*
*/
#include <asm-generic/errno.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
@@ -27,32 +28,6 @@
#define LOGPPMGW(pool_member, level, fmt, args...) \
LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
/* Get a human readable name for a given pool member. */
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
{
const struct mgcp_client *mpcp_client;
struct mgcp_client mpcp_client_dummy;
static char name[512];
const char *description;
if (!pool_member)
return "(null)";
/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
* initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
if (!pool_member->client) {
memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
mpcp_client = &mpcp_client_dummy;
} else {
mpcp_client = pool_member->client;
}
description = mgcp_client_name(mpcp_client);
snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
return name;
}
/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
* mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
* \param[in] talloc_ctx talloc context. */
@@ -64,7 +39,7 @@ struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
if (!pool)
return NULL;
INIT_LLIST_HEAD(&pool->pool);
INIT_LLIST_HEAD(&pool->member_list);
return pool;
}
@@ -77,29 +52,11 @@ unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
struct mgcp_client_pool_member *pool_member;
unsigned int pool_members_initialized = 0;
llist_for_each_entry(pool_member, &pool->pool, list) {
llist_for_each_entry(pool_member, &pool->member_list, list) {
/* Initialize client */
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
if (!pool_member->client) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
continue;
}
/* Set backpointer so that we can detect later that this MGCP client is managed
* by this pool. */
pool_member->client->pool = pool;
/* Connect client */
if (mgcp_client_connect2(pool_member->client, 0)) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
pool_member->conf.remote_addr, pool_member->conf.remote_port);
talloc_free(pool_member->client);
pool_member->client = NULL;
continue;
}
pool_members_initialized++;
if (mgcp_client_pool_member_reinit_client(pool_member) == 0)
pool_members_initialized++;
}
return pool_members_initialized;
@@ -118,23 +75,37 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
pool->mgcp_client_single = mgcp_client;
}
/*! Lookup the selected MGCP client config by its reference number */
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
{
struct mgcp_client_pool_member *pool_member;
llist_for_each_entry(pool_member, &pool->member_list, list) {
if (pool_member->nr == nr)
return pool_member;
}
return NULL;
}
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
* pool member that is suitable (has a client, is not blocked, has a low load). */
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
{
struct mgcp_client_pool_member *pool_member;
struct mgcp_client_pool_member *pool_member_picked = NULL;
unsigned int n_pool_members = llist_count(&pool->pool);
unsigned int n_pool_members = 0;
llist_for_each_entry(pool_member, &pool->pool, list) {
llist_for_each_entry(pool_member, &pool->member_list, list) {
n_pool_members++;
if (pool_member->blocked == false && pool_member->client) {
if (!pool_member_picked)
pool_member_picked = pool_member;
else if (pool_member_picked->refcount > pool_member->refcount)
pool_member_picked = pool_member;
} else {
LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
pool_member->nr);
LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u)\n",
__func__, pool_member->nr, pool_member->blocked, !!pool_member->client);
}
}
@@ -163,26 +134,24 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
* by the application code. */
/* When the pool is empty, return a single MGCP client if it is registered. */
if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
mgcp_client_name(pool->mgcp_client_single));
return pool->mgcp_client_single;
}
/* Abort when the pool is empty */
if (llist_empty(&pool->pool)) {
if (llist_empty(&pool->member_list)) {
LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
return NULL;
}
/* Pick a suitable pool member */
pool_member = mgcp_client_pool_pick(pool);
if (pool_member) {
pool_member->refcount++;
return pool_member->client;
}
if (!pool_member)
return NULL;
return NULL;
return mgcp_client_pool_member_get(pool_member);
}
/*! put an MGCP client back into the pool (decrement reference counter).
@@ -194,23 +163,130 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
{
struct mgcp_client_pool_member *pool_member;
struct mgcp_client_pool *pool;
if (!mgcp_client)
return;
if (mgcp_client->pool)
pool = mgcp_client->pool;
else
if (!mgcp_client->pool_member)
return;
pool_member = mgcp_client->pool_member;
llist_for_each_entry(pool_member, &pool->pool, list) {
if (pool_member->client == mgcp_client) {
if (pool_member->refcount == 0) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
return;
}
pool_member->refcount--;
}
if (pool_member->refcount == 0) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
return;
}
pool_member->refcount--;
}
/***************************
* mgcp_client_pool_member:
***************************/
/*! Allocate an mgcp_client_pool_member.
* \param[in] pool MGCP client pool descriptor.
* \param[in] nr Reference number of the pool member.
*/
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr)
{
struct mgcp_client_pool_member *pool_member;
pool_member = talloc_zero(pool, struct mgcp_client_pool_member);
OSMO_ASSERT(pool_member);
mgcp_client_conf_init(&pool_member->conf);
pool_member->pool = pool;
pool_member->nr = nr;
llist_add_tail(&pool_member->list, &pool->member_list);
return pool_member;
}
/*! Free an mgcp_client_pool_member allocated through mgcp_client_pool_member_alloc().
* \param[in] pool_member MGCP client pool descriptor.
*
* It also frees the associated MGCP client if present.
*/
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member)
{
llist_del(&pool_member->list);
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
talloc_free(pool_member);
}
/*! Recreate and reconnect the MGCP client associated to the pool descriptor.
* \param[in] pool_member MGCP client pool descriptor.
*/
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member)
{
/* Get rid of a possibly existing old MGCP client instance first */
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
/* Initialize client */
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
if (!pool_member->client) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
return -EINVAL;
}
/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
pool_member->client->pool_member = pool_member;
/* Connect client */
if (mgcp_client_connect(pool_member->client)) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
pool_member->conf.remote_addr, pool_member->conf.remote_port);
talloc_free(pool_member->client);
pool_member->client = NULL;
return -ECONNABORTED;
}
return 0;
}
/* Get a human readable name for a given pool member. */
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
{
const struct mgcp_client *mpcp_client;
struct mgcp_client mpcp_client_dummy;
static char name[512];
const char *description;
if (!pool_member)
return "(null)";
/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
* initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
if (!pool_member->client) {
memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
mpcp_client = &mpcp_client_dummy;
} else {
mpcp_client = pool_member->client;
}
description = mgcp_client_name(mpcp_client);
snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
return name;
}
/*! Get the MGCP client associated with the pool reference from the pool (increment reference counter).
* \param[in] pool_member MGCP client pool descriptor.
* \returns MGCP client descriptor, NULL if no member was not ready.
*/
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member)
{
pool_member->refcount++;
return pool_member->client;
}
/*! Get whether the MGCP client associated with the pool reference is blocked by policy.
* \param[in] pool_member MGCP client pool descriptor.
* \returns true if blocked, false otherwise
*/
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member)
{
return pool_member->blocked;
}

View File

@@ -32,10 +32,11 @@
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool.h>
#define MGW_STR MGCP_CLIENT_MGW_STR
/* Only common (non-pooled) VTY connands will use this talloc context. All
/* Only common (non-pooled) VTY commands will use this talloc context. All
* pooled VTY commands will use the pool (global_mgcp_client_pool) as
* talloc context. */
static void *global_mgcp_client_ctx = NULL;
@@ -51,13 +52,18 @@ struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
{
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
return vty->index;
else
return global_mgcp_client_conf;
/* Global single MGCP config, deprecated: */
vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
"You should consider reading User Manual and migrating to 'mgw' node.%s",
VTY_NEWLINE);
return global_mgcp_client_conf;
}
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
"mgw local-ip " VTY_IPV46_CMD,
MGW_STR "local bind to connect to MGW from\n"
"local-ip " VTY_IPV46_CMD,
"local bind to connect to MGW from\n"
"local bind IPv4 address\n"
"local bind IPv6 address\n")
{
@@ -72,10 +78,16 @@ ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
"mgcpgw local-ip A.B.C.D",
MGW_STR "local bind to connect to MGCP gateway with\n"
"local bind IP address\n")
ALIAS_DEPRECATED(cfg_mgw_local_ip,
cfg_mgw_mgw_local_ip_cmd,
"mgw local-ip " VTY_IPV46_CMD,
MGW_STR "local bind to connect to MGW from\n"
"local bind IPv4 address\n"
"local bind IPv6 address\n")
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
"mgw local-port <0-65535>",
MGW_STR "local port to connect to MGW from\n"
"local-port <0-65535>",
"local port to connect to MGW from\n"
"local bind port\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
@@ -87,10 +99,15 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
"mgcpgw local-port <0-65535>",
MGW_STR "local bind to connect to MGCP gateway with\n"
"local bind port\n")
ALIAS_DEPRECATED(cfg_mgw_local_port,
cfg_mgw_mgw_local_port_cmd,
"mgw local-port <0-65535>",
MGW_STR "local port to connect to MGW from\n"
"local bind port\n")
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
"mgw remote-ip " VTY_IPV46_CMD,
MGW_STR "remote IP address to reach the MGW at\n"
"remote-ip " VTY_IPV46_CMD,
"remote IP address to reach the MGW at\n"
"remote IPv4 address\n"
"remote IPv6 address\n")
{
@@ -104,10 +121,16 @@ ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
"mgcpgw remote-ip A.B.C.D",
MGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind IP address\n")
ALIAS_DEPRECATED(cfg_mgw_remote_ip,
cfg_mgw_mgw_remote_ip_cmd,
"mgw remote-ip " VTY_IPV46_CMD,
MGW_STR "remote IP address to reach the MGW at\n"
"remote IPv4 address\n"
"remote IPv6 address\n")
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
"mgw remote-port <0-65535>",
MGW_STR "remote port to reach the MGW at\n"
"remote-port <0-65535>",
"remote port to reach the MGW at\n"
"remote port\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
@@ -119,8 +142,13 @@ ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
"mgcpgw remote-port <0-65535>",
MGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind port\n")
ALIAS_DEPRECATED(cfg_mgw_remote_port,
cfg_mgw_mgw_remote_port_cmd,
"mgw remote-port <0-65535>",
MGW_STR "remote port to reach the MGW at\n"
"remote port\n")
DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
"mgw endpoint-range <1-65534> <1-65534>",
MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
"-\n" "-\n")
@@ -130,7 +158,7 @@ DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
VTY_NEWLINE);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
ALIAS_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
"mgcpgw endpoint-range <1-65534> <1-65534>",
MGW_STR "usable range of endpoint identifiers\n"
"set first useable endpoint identifier\n"
@@ -158,8 +186,8 @@ ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
DEFUN(cfg_mgw_endpoint_domain_name,
cfg_mgw_endpoint_domain_name_cmd,
"mgw endpoint-domain NAME",
MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
"endpoint-domain NAME",
"Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
"Domain name, should be alphanumeric.\n")
{
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
@@ -172,11 +200,16 @@ DEFUN(cfg_mgw_endpoint_domain_name,
}
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_endpoint_domain_name,
cfg_mgw_mgw_endpoint_domain_name_cmd,
"mgw endpoint-domain NAME",
MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
"Domain name, should be alphanumeric.\n")
DEFUN(cfg_mgw_reset_ep_name,
cfg_mgw_reset_ep_name_cmd,
"mgw reset-endpoint NAME",
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
"reset-endpoint NAME",
"Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
"e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
{
@@ -214,11 +247,17 @@ DEFUN(cfg_mgw_reset_ep_name,
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_reset_ep_name,
cfg_mgw_mgw_reset_ep_name_cmd,
"mgw reset-endpoint NAME",
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
"e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
DEFUN(cfg_mgw_no_reset_ep_name,
cfg_mgw_no_reset_ep_name_cmd,
"no mgw reset-endpoint NAME",
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
"no reset-endpoint NAME",
NO_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
{
struct reset_ep *reset_ep;
@@ -235,6 +274,11 @@ DEFUN(cfg_mgw_no_reset_ep_name,
vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
cfg_mgw_mgw_no_reset_ep_name_cmd,
"no mgw reset-endpoint NAME",
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
{
@@ -242,33 +286,36 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
int port;
struct reset_ep *reset_ep;
if (conf->description)
/* If caller doesn't the MGW pool API (mgcp_client_pool_vty_init was never called),
* then the "mgw" cmd prefix must be added since the old node always contained it.
*/
const char *mgw_prefix = global_mgcp_client_pool ? "" : "mgw ";
if (conf->description) /* description never had "mgw" prefix even on old node: */
vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
addr = conf->local_addr;
if (addr)
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
VTY_NEWLINE);
vty_out(vty, "%s%slocal-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
port = conf->local_port;
if (port >= 0)
vty_out(vty, "%smgw local-port %u%s", indent,
vty_out(vty, "%s%slocal-port %u%s", indent, mgw_prefix,
(uint16_t)port, VTY_NEWLINE);
addr = conf->remote_addr;
if (addr)
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
VTY_NEWLINE);
vty_out(vty, "%s%sremote-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
port = conf->remote_port;
if (port >= 0)
vty_out(vty, "%smgw remote-port %u%s", indent,
vty_out(vty, "%s%sremote-port %u%s", indent, mgw_prefix,
(uint16_t)port, VTY_NEWLINE);
if (conf->endpoint_domain_name[0])
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
vty_out(vty, "%s%sendpoint-domain %s%s", indent, mgw_prefix,
conf->endpoint_domain_name, VTY_NEWLINE);
llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -279,6 +326,11 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
int mgcp_client_config_write(struct vty *vty, const char *indent)
{
/* If caller supports MGW pool API (mgcp_client_pool_vty_init was
* called), then skip printing any config in this node and print it when
* the whole 'mgw' node is printed. */
if (global_mgcp_client_pool)
return CMD_SUCCESS;
return config_write(vty, indent, global_mgcp_client_conf);
}
@@ -286,15 +338,15 @@ static void vty_init_common(void *talloc_ctx, int node)
{
global_mgcp_client_ctx = talloc_ctx;
install_lib_element(node, &cfg_mgw_local_ip_cmd);
install_lib_element(node, &cfg_mgw_local_port_cmd);
install_lib_element(node, &cfg_mgw_remote_ip_cmd);
install_lib_element(node, &cfg_mgw_remote_port_cmd);
install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
/* deprecated 'mgw' commands ('mgw' prepended as first arg) */
install_lib_element(node, &cfg_mgw_mgw_local_ip_cmd);
install_lib_element(node, &cfg_mgw_mgw_local_port_cmd);
install_lib_element(node, &cfg_mgw_mgw_remote_ip_cmd);
install_lib_element(node, &cfg_mgw_mgw_remote_port_cmd);
install_lib_element(node, &cfg_mgw_mgw_endpoint_range_cmd);
install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
osmo_fsm_vty_add_cmds();
}
@@ -319,38 +371,62 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
vty_init_common(talloc_ctx, node);
}
static int config_write_pool(struct vty *vty)
/* Mark whether user called mgcp_client_pool_config_write() and hence support new API */
static bool mgcp_client_pool_config_write_called = false;
static int _mgcp_client_pool_config_write(struct vty *vty, const char *indent)
{
struct mgcp_client_pool *pool = global_mgcp_client_pool;
struct mgcp_client_pool_member *pool_member;
unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
char *indent = talloc_zero_size(vty, indent_buf_len);
unsigned int subindent_buf_len;
char *subindent;
snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
if (!indent)
indent = pool->vty_indent ? : "";
subindent_buf_len = strlen(indent) + 1 + 1;
subindent = talloc_zero_size(vty, subindent_buf_len);
llist_for_each_entry(pool_member, &pool->pool, list) {
vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
config_write(vty, indent, &pool_member->conf);
snprintf(subindent, subindent_buf_len, "%s ", indent);
llist_for_each_entry(pool_member, &pool->member_list, list) {
vty_out(vty, "%smgw %u%s", indent, pool_member->nr, VTY_NEWLINE);
config_write(vty, subindent, &pool_member->conf);
}
talloc_free(indent);
/* MGW pool API is supported by user (global_mgcp_client_pool is set
* because mgcp_client_pool_vty_init was called). If single MGW was
* configured through old VTY and no mgw in the new MGW pool VTY is
* replacing it, then output the single MGW converted to the new MGW
* pool VTY. */
if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
vty_out(vty, "%smgw 0%s", indent, VTY_NEWLINE);
config_write(vty, subindent, global_mgcp_client_conf);
}
talloc_free(subindent);
return CMD_SUCCESS;
}
/* Lookup the selected MGCP client config by its reference number */
static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
/* Deprecated, used for backward compatibility with older users which didn't call
* mgcp_client_pool_config_write(): */
static int config_write_pool(struct vty *vty)
{
struct mgcp_client_pool_member *pool_member = NULL;
struct mgcp_client_pool_member *pool_member_tmp;
if (mgcp_client_pool_config_write_called)
return CMD_SUCCESS;
llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
if (pool_member_tmp->nr == nr) {
pool_member = pool_member_tmp;
break;
}
}
return _mgcp_client_pool_config_write(vty, NULL);
}
return pool_member;
/*! Write out MGCP client config to VTY.
* \param[in] vty VTY to which we should print.
* \param[in] indent string used for indentation (e.g. " ").
If NULL, indentation passed during mgcp_client_pool_vty_init() will be used.
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
int mgcp_client_pool_config_write(struct vty *vty, const char *indent)
{
/* Tell internal node write function that the user supports calling proper API: */
mgcp_client_pool_config_write_called = true;
return _mgcp_client_pool_config_write(vty, indent);
}
DEFUN_ATTR(cfg_mgw,
@@ -359,13 +435,10 @@ DEFUN_ATTR(cfg_mgw,
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member;
pool_member = pool_member_by_nr(nr);
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
if (!pool_member) {
pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
pool_member = mgcp_client_pool_member_alloc(global_mgcp_client_pool, nr);
OSMO_ASSERT(pool_member);
mgcp_client_conf_init(&pool_member->conf);
pool_member->nr = nr;
llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
}
vty->index = &pool_member->conf;
@@ -382,7 +455,7 @@ DEFUN_ATTR(cfg_no_mgw,
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member;
pool_member = pool_member_by_nr(nr);
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
@@ -395,12 +468,7 @@ DEFUN_ATTR(cfg_no_mgw,
return CMD_WARNING;
}
llist_del(&pool_member->list);
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
talloc_free(pool_member);
mgcp_client_pool_member_free(pool_member);
return CMD_SUCCESS;
}
@@ -412,7 +480,7 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
@@ -425,32 +493,10 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
return CMD_WARNING;
}
/* Get rid of a possibly existing old MGCP client instance first */
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
/* Create a new MGCP client instance with the current config */
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
if (!pool_member->client) {
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
mgcp_client_pool_member_name(pool_member));
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
pool_member->client->pool = global_mgcp_client_pool;
/* Connect client */
if (mgcp_client_connect(pool_member->client)) {
if (mgcp_client_pool_member_reinit_client(pool_member) < 0) {
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
pool_member->conf.remote_port);
talloc_free(pool_member->client);
pool_member->client = NULL;
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
return CMD_WARNING;
@@ -466,7 +512,7 @@ DEFUN_ATTR(mgw_block, mgw_block_cmd,
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
@@ -483,7 +529,7 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
@@ -493,20 +539,20 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
return CMD_SUCCESS;
}
DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
{
vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
struct mgcp_client_pool_member *pool_member;
if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
if (llist_empty(&global_mgcp_client_pool->member_list) && global_mgcp_client_pool->mgcp_client_single) {
vty_out(vty, "%% (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
return CMD_SUCCESS;
} else if (llist_empty(&global_mgcp_client_pool->pool)) {
} else if (llist_empty(&global_mgcp_client_pool->member_list)) {
vty_out(vty, "%% (pool is empty)%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
vty_out(vty, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
vty_out(vty, "%% mgcp-client: %s%s", pool_member->client ? "connected" : "disconnected",
VTY_NEWLINE);
@@ -520,7 +566,8 @@ DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information abo
* (called once at startup by the application process).
* \param[in] parent_node identifier of the parent node on which the mgw node appears.
* \param[in] mgw_node identifier that should be used with the newly installed MGW node.
* \param[in] indent indentation string to match the indentation in the VTY config
* \param[in] indent indentation string to match the indentation in the VTY config.
If NULL, it must be passed explicitly each time mgcp_client_pool_config_write() is called.
* \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
{
@@ -528,11 +575,12 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
OSMO_ASSERT(pool);
/* Never allow this function to be called twice on the same pool */
OSMO_ASSERT(!pool->vty_indent);
OSMO_ASSERT(!pool->vty_node);
pool->vty_indent = talloc_strdup(pool, indent);
OSMO_ASSERT(pool->vty_indent);
if (indent) {
pool->vty_indent = talloc_strdup(pool, indent);
OSMO_ASSERT(pool->vty_indent);
}
pool->vty_node = talloc_zero(pool, struct cmd_node);
OSMO_ASSERT(pool->vty_node);
pool->vty_node->node = mgw_node;
@@ -542,8 +590,19 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
install_lib_element(parent_node, &cfg_mgw_cmd);
install_lib_element(parent_node, &cfg_no_mgw_cmd);
/* Note: config_write_pool is deprecated and user is expected to
* manually call mgcp_client_pool_config_write() when printing the VTY
* config */
install_node(pool->vty_node, config_write_pool);
vty_init_common(pool, mgw_node);
install_lib_element(mgw_node, &cfg_mgw_local_ip_cmd);
install_lib_element(mgw_node, &cfg_mgw_local_port_cmd);
install_lib_element(mgw_node, &cfg_mgw_remote_ip_cmd);
install_lib_element(mgw_node, &cfg_mgw_remote_port_cmd);
install_lib_element(mgw_node, &cfg_mgw_rtp_bts_base_port_cmd);
install_lib_element(mgw_node, &cfg_mgw_endpoint_domain_name_cmd);
install_lib_element(mgw_node, &cfg_mgw_reset_ep_name_cmd);
install_lib_element(mgw_node, &cfg_mgw_no_reset_ep_name_cmd);
install_element(mgw_node, &cfg_description_cmd);
@@ -551,7 +610,7 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
install_lib_element(ENABLE_NODE, &mgw_block_cmd);
install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
install_lib_element_ve(&mgw_snow_cmd);
install_lib_element_ve(&mgw_show_cmd);
global_mgcp_client_pool = pool;
}

View File

@@ -45,7 +45,6 @@ libosmo_mgcp_a_SOURCES = \
mgcp_stat.c \
mgcp_endp.c \
mgcp_trunk.c \
mgcp_ctrl.c \
mgcp_ratectr.c \
mgcp_e1.c \
mgcp_iuup.c \

View File

@@ -345,6 +345,18 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
return -EINVAL;
}
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
{
if (codec->param_present == false)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
if (strcmp(codec->subtype_name, "AMR") != 0)
return false;
return true;
}
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
* Media Type Registration":

View File

@@ -37,7 +37,7 @@
#include <osmocom/core/timer.h>
#include <ctype.h>
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
static const struct rate_ctr_group_desc rate_ctr_group_desc = {
.group_name_prefix = "conn_rtp",
.group_description = "rtp connection statistics",
.class_id = 1,
@@ -95,15 +95,21 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
static atomic_uint rate_ctr_index = 0;
conn_rtp->type = MGCP_RTP_DEFAULT;
conn_rtp->osmux.cid_allocated = false;
conn_rtp->osmux.cid = 0;
/* Osmux specific defaults, only used if conn is later on Osmux-enabled: */
conn_rtp->osmux.state = OSMUX_STATE_DISABLED;
conn_rtp->osmux.local_cid_allocated = false;
conn_rtp->osmux.local_cid = 0;
conn_rtp->osmux.remote_cid_present = false;
conn_rtp->osmux.remote_cid = 0;
/* backpointer to the generic part of the connection */
conn->u.rtp.conn = conn;
end->rtp.fd = -1;
end->rtcp.fd = -1;
end->rtp_port = end->rtcp_port = 0;
memset(&end->addr, 0, sizeof(end->addr));
end->rtcp_port = 0;
talloc_free(end->fmtp_extra);
end->fmtp_extra = NULL;
@@ -113,12 +119,12 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
end->output_enabled = false;
end->maximum_packet_time = -1;
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
if (!conn_rtp->rate_ctr_group)
conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
if (!conn_rtp->ctrg)
return -1;
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
/* Make sure codec table is reset */
mgcp_codec_reset_all(conn_rtp);
@@ -134,7 +140,7 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
if (mgcp_conn_rtp_is_iuup(conn_rtp))
mgcp_conn_iuup_cleanup(conn_rtp);
mgcp_free_rtp_port(&conn_rtp->end);
rate_ctr_group_free(conn_rtp->rate_ctr_group);
rate_ctr_group_free(conn_rtp->ctrg);
mgcp_codec_reset_all(conn_rtp);
}
@@ -263,7 +269,7 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
{
struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
if (all_stats == NULL || conn_stats == NULL)
return;
@@ -360,14 +366,38 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
/* Dump RTP connection */
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
"rtp:%u rtcp:%u)",
conn->name,
conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
ntohs(conn->u.rtp.end.rtp_port),
ntohs(conn->u.rtp.end.rtcp_port));
switch (conn->u.rtp.type) {
case MGCP_RTP_DEFAULT:
/* Dump RTP connection */
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
"rtp:%u rtcp:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
ntohs(conn->u.rtp.end.rtcp_port));
break;
case MGCP_RTP_OSMUX:
snprintf(str, sizeof(str), "(%s/osmux, id:0x%s, ip:%s, "
"port:%u CID:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
conn->u.rtp.osmux.local_cid);
break;
case MGCP_RTP_IUUP:
snprintf(str, sizeof(str), "(%s/iuup, id:0x%s, ip:%s, "
"port:%u)",
conn->name, conn->id,
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
break;
default:
/* Should not happen, we should be able to dump
* every possible connection type. */
snprintf(str, sizeof(str), "(unknown conn_rtp connection type %u)",
conn->u.rtp.type);
break;
}
break;
default:

View File

@@ -1,36 +0,0 @@
/*
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/ctrl/control_if.h>
#include <osmocom/mgcp/mgcp.h>
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
void **node_data, int *i)
{
return 0;
}
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
const char *bind_addr, uint16_t port)
{
return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
_LAST_CTRL_NODE);
}

View File

@@ -496,7 +496,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
}
}
/* !Equip E1 endpoint with I.460 mux resources.
/*! Equip E1 endpoint with I.460 mux resources.
* \param[in] endp endpoint to equip
* \param[in] ts E1 timeslot number.
* \param[in] ss E1 subslot number.

View File

@@ -98,7 +98,11 @@ static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t f
uint8_t rfci_cnt = 0;
unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
OSMO_ASSERT(irp);
if (!irp) {
/* No IuUP Initialization has occured on the IuUP side yet. Return error and drop the RTP data, until
* the IuUP Initialization has configured the link. */
return -1;
}
/* TODO: cache this somehow */
for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
@@ -270,9 +274,9 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
return ft;
}
msgb_pull_to_l3(msg);
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
amr_hdr->cmr = 15; /* no change */
amr_hdr->f = 0;
@@ -291,6 +295,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
msgb_trim(msg, amr_length);
LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR BE: ft %d, len %zd\n", ft, amr_length);
}
rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
*rtp_hdr = (struct rtp_hdr){
@@ -342,8 +347,7 @@ static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osm
return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
case MGCP_RTP_DEFAULT:
return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
case MGCP_OSMUX_BSC:
case MGCP_OSMUX_BSC_NAT:
case MGCP_RTP_OSMUX:
default:
LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
"Forward of IuUP payload to RTP connection type %u not supported!\n",
@@ -490,7 +494,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
return 0;
}
@@ -506,14 +510,13 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port));
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
(char *)hdr, buflen);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
if (len <= 0)
return len;
@@ -618,9 +621,8 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
force_output_enabled = true;
/* Fill in the peer address so that we can send Init-ACK back: */
prev_rem_addr = conn_rtp_src->end.addr;
prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
prev_rem_rtp_port = osmo_sockaddr_port(&conn_rtp_src->end.addr.u.sa);
conn_rtp_src->end.addr = *mc->from_addr;
conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
}
rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
@@ -628,7 +630,7 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
if (force_output_enabled) {
conn_rtp_src->end.output_enabled = prev_output_enabled;
conn_rtp_src->end.addr = prev_rem_addr;
conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
osmo_sockaddr_set_port(&conn_rtp_src->end.addr.u.sa, prev_rem_rtp_port);
}
return rc;
@@ -670,7 +672,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
"Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
goto free_ret;
}
if (amr_hdr->ft >= AMR_FT_MAX) {
if (!osmo_amr_ft_valid(amr_hdr->ft)) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
goto free_ret;
}
@@ -678,19 +680,22 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
goto free_ret;
}
irp->u.data.fqc = amr_hdr->q;
irp->u.data.fqc = amr_hdr->q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
irp->u.data.rfci = rfci;
msgb_pull(msg, 2);
LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR OA -> IuUP: ft %d -> rfci %d len %d\n",
amr_hdr->ft, rfci, msgb_length(msg));
} else {
uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
int8_t ft;
uint8_t q;
if (msgb_length(msg) < 2) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
"Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
goto free_ret;
}
ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
if (ft >= AMR_FT_MAX) {
if (!osmo_amr_ft_valid(ft)) {
LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
goto free_ret;
}
@@ -698,7 +703,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
goto free_ret;
}
irp->u.data.fqc = ((amr_bwe_hdr[1] & 0x40) >> 6);
q = amr_bwe_hdr[1] & 0x40;
irp->u.data.fqc = q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
irp->u.data.rfci = rfci;
rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
if (rc < 0) {
@@ -706,6 +712,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
return rc;
}
msgb_trim(msg, iuup_length);
LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR BE -> IuUP: ft %d -> rfci %d len %d\n",
ft, rfci, msgb_length(msg));
}
irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));

View File

@@ -202,7 +202,7 @@ int mgcp_parse_osmux_cid(const char *line)
osmux_cid, OSMUX_CID_MAX);
return -2;
}
LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
return osmux_cid;
}

View File

@@ -54,15 +54,10 @@
#define RTP_MAX_DROPOUT 3000
#define RTP_MAX_MISORDER 100
enum rtp_proto {
MGCP_PROTO_RTP,
MGCP_PROTO_RTCP,
};
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
int id, int inc)
{
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
/* add to both the per-connection and the global stats */
@@ -70,49 +65,68 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
}
static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
{
rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
}
static int rx_rtp(struct msgb *msg);
static bool addr_is_any(const struct osmo_sockaddr *osa)
{
if (osa->u.sa.sa_family == AF_INET6) {
struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
return memcmp(&osa->u.sin6.sin6_addr,
&ip6_any, sizeof(ip6_any)) == 0;
} else {
return osa->u.sin.sin_addr.s_addr == 0;
}
}
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
{
return rtp_end->rtp_port && !addr_is_any(&rtp_end->addr);
return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
(osmo_sockaddr_is_any(&rtp_end->addr) == 0);
}
/*! Determine the local rtp bind IP-address.
* \param[out] addr caller provided memory to store the resulting IP-Address.
* \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
* \ returns 0 on success, -1 if no local address could be provided.
*
* The local bind IP-address is automatically selected by probing the
* IP-Address of the interface that is pointing towards the remote IP-Address,
* if no remote IP-Address is known yet, the statically configured
* IP-Addresses are used as fallback. */
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
{
struct mgcp_endpoint *endp;
const struct mgcp_endpoint *endp = conn->conn->endp;
const struct mgcp_config *cfg = endp->trunk->cfg;
char ipbuf[INET6_ADDRSTRLEN];
int rc;
endp = conn->conn->endp;
bool rem_addr_set = !addr_is_any(&conn->end.addr);
char *bind_addr;
bool rem_addr_set = osmo_sockaddr_is_any(&conn->end.addr) == 0;
const char *bind_addr;
/* Osmux: No smart IP addresses allocation is supported yet. Simply
* return the one set in VTY config: */
if (mgcp_conn_rtp_is_osmux(conn)) {
if (rem_addr_set) {
/* Match IP version with what was requested from remote: */
bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
cfg->osmux.local_addr_v6 :
cfg->osmux.local_addr_v4;
} else {
/* Choose any of the bind addresses, preferring v6 over v4 if available: */
bind_addr = cfg->osmux.local_addr_v6;
if (!bind_addr)
bind_addr = cfg->osmux.local_addr_v4;
}
if (!bind_addr) {
LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
"Unable to locate local Osmux address, check your configuration! v4=%u v6=%u remote_known=%s\n",
!!cfg->osmux.local_addr_v4,
!!cfg->osmux.local_addr_v6,
rem_addr_set ? osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf) : "no");
return -1;
}
LOGPCONN(conn->conn, DOSMUX, LOGL_DEBUG,
"Using configured osmux bind ip as local bind ip %s\n",
bind_addr);
osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
return 0;
}
/* Try probing the local IP-Address */
if (endp->trunk->cfg->net_ports.bind_addr_probe && rem_addr_set) {
if (cfg->net_ports.bind_addr_probe && rem_addr_set) {
rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
if (rc < 0)
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
@@ -121,22 +135,22 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
"selected local rtp bind ip %s by probing using remote ip %s\n",
addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
return;
return 0;
}
}
/* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
/* Select from preconfigured IP-Addresses. */
if (rem_addr_set) {
/* Check there is a bind IP for the RTP traffic configured,
* if so, use that IP-Address */
bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
endp->trunk->cfg->net_ports.bind_addr_v6 :
endp->trunk->cfg->net_ports.bind_addr_v4;
cfg->net_ports.bind_addr_v6 :
cfg->net_ports.bind_addr_v4;
} else {
/* Choose any of the bind addresses, preferring v6 over v4 */
bind_addr = endp->trunk->cfg->net_ports.bind_addr_v6;
bind_addr = cfg->net_ports.bind_addr_v6;
if (!strlen(bind_addr))
bind_addr = endp->trunk->cfg->net_ports.bind_addr_v4;
bind_addr = cfg->net_ports.bind_addr_v4;
}
if (strlen(bind_addr)) {
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
@@ -146,11 +160,12 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
/* No specific bind IP is configured for the RTP traffic, so
* assume the IP where we listen for incoming MGCP messages
* as bind IP */
bind_addr = endp->trunk->cfg->source_addr;
bind_addr = cfg->source_addr;
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
}
osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
return 0;
}
/* This does not need to be a precision timestamp and
@@ -676,7 +691,7 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
{
struct rtp_hdr *rtp_hdr;
if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
LOGPENDP(endp, DRTP, LOGL_ERROR, "RTP packet too short (%d < %zu)\n",
msgb_length(msg), sizeof(struct rtp_hdr));
return -EINVAL;
}
@@ -702,11 +717,18 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
return 0;
}
/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
/*! Convert msg to AMR RTP framing mode specified by target_is_oa.
* \param[in] endp MGCP Endpoint where this message belongs to (used for logging purposes)
* \param[in] msg Message containing an AMR RTP payload (in octet-aligned or bandwidth-efficient format).
* \param[in] target_is_oa the target framing mode that msg will contain after this function succeeds.
* \returns The size of the new RTP AMR content on success, negative on error.
*
* For AMR RTP two framing modes are defined RFC3267. There is a bandwidth
* efficient encoding scheme where all fields are packed together one after
* another and an octet aligned mode where all fields are aligned to octet
* boundaries. This function is used to convert between the two modes */
static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
* boundaries. This function is used to convert between the two modes.
*/
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
bool target_is_oa)
{
/* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
@@ -715,6 +737,7 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
struct rtp_hdr *rtp_hdr;
unsigned int payload_len;
int rc;
bool orig_is_oa;
if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
@@ -722,10 +745,10 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
}
rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
orig_is_oa = osmo_amr_is_oa(rtp_hdr->data, payload_len);
if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
if (orig_is_oa) {
if (!target_is_oa)
/* Input data is oa an target format is bwe
* ==> convert */
@@ -747,27 +770,16 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
}
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"AMR RTP packet conversion failed\n");
"RTP AMR packet conversion %s->%s failed: %s\n",
orig_is_oa ? "OA" : "BWE",
target_is_oa ? "OA" : "BWE",
osmo_hexdump(rtp_hdr->data, payload_len));
return -EINVAL;
}
return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
}
/* Check if a conversion between octet-aligned and bandwith-efficient mode is
* indicated. */
static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
{
if (codec->param_present == false)
return false;
if (!codec->param.amr_octet_aligned_present)
return false;
if (strcmp(codec->subtype_name, "AMR") != 0)
return false;
return true;
}
/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
* Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
static int amr_oa_check(char *data, int len)
@@ -826,7 +838,7 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
{
char ipbuf[INET6_ADDRSTRLEN];
if (addr_is_any(&conn->end.addr)) {
if (osmo_sockaddr_is_any(&conn->end.addr) != 0) {
switch (conn->conn->mode) {
case MGCP_CONN_LOOPBACK:
/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
@@ -875,14 +887,14 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
* the same as the remote port where we transmit outgoing RTP traffic
* to (set by MDCX). We use this to check the origin of the data for
* plausibility. */
if (ntohs(conn->end.rtp_port) != osmo_sockaddr_port(&addr->u.sa) &&
if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"data from wrong source port: %d, ",
osmo_sockaddr_port(&addr->u.sa));
LOGPC(DRTP, LOGL_ERROR,
"expected: %d for RTP or %d for RTCP\n",
ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
osmo_sockaddr_port(&conn->end.addr.u.sa), ntohs(conn->end.rtcp_port));
LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
return -1;
}
@@ -895,28 +907,29 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
static int check_rtp_destin(struct mgcp_conn_rtp *conn)
{
char ipbuf[INET6_ADDRSTRLEN];
bool ip_is_any = addr_is_any(&conn->end.addr);
bool ip_is_any = osmo_sockaddr_is_any(&conn->end.addr) != 0;
uint16_t port = osmo_sockaddr_port(&conn->end.addr.u.sa);
/* Note: it is legal to create a connection but never setting a port
* and IP-address for outgoing data. */
if (ip_is_any && conn->end.rtp_port == 0) {
if (ip_is_any && port == 0) {
LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
"destination IP-address and rtp port is not (yet) known (%s:%u)\n",
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
return -1;
}
if (ip_is_any) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"destination IP-address is invalid (%s:%u)\n",
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
return -1;
}
if (conn->end.rtp_port == 0) {
if (port == 0) {
LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
"destination rtp port is invalid (%s:%u)\n",
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
return -1;
}
@@ -980,9 +993,16 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
return 0;
}
/* Send RTP data. Possible options are standard RTP packet
* transmission or trsmission via an osmux connection */
static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
/*! Dispatch msg bridged from the sister conn in the endpoint.
* \param[in] conn_dst The destination conn that should handle and transmit the content to
* its peer outside MGW.
* \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
* \returns bytes sent, -1 on error.
*
* Possible options are standard RTP packet transmission, transmission
* via IuUP or transmission via an osmux connection.
*/
static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
enum rtp_proto proto = mc->proto;
@@ -1007,12 +1027,11 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
"using mgcp_send() to forward data directly\n");
return mgcp_send(endp, proto == MGCP_PROTO_RTP,
mc->from_addr, msg, conn_src, conn_dst);
case MGCP_OSMUX_BSC_NAT:
case MGCP_OSMUX_BSC:
case MGCP_RTP_OSMUX:
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"endpoint type is MGCP_OSMUX_BSC_NAT, "
"endpoint type is MGCP_RTP_OSMUX, "
"using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
return conn_osmux_send_rtp(conn_dst, msg);
case MGCP_RTP_IUUP:
if (proto == MGCP_PROTO_RTP) {
LOGPENDP(endp, DRTP, LOGL_DEBUG,
@@ -1039,26 +1058,22 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
/*! send udp packet.
* \param[in] fd associated file descriptor.
* \param[in] addr destination ip-address.
* \param[in] port destination UDP port (network byte order).
* \param[in] buf buffer that holds the data to be send.
* \param[in] len length of the data to be sent.
* \returns bytes sent, -1 on error. */
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len)
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
{
char ipbuf[INET6_ADDRSTRLEN];
size_t addr_len;
bool is_ipv6 = addr->u.sa.sa_family == AF_INET6;
LOGP(DRTP, LOGL_DEBUG,
"sending %i bytes length packet to %s:%u ...\n", len,
osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
ntohs(port));
osmo_sockaddr_port(&addr->u.sa));
if (is_ipv6) {
addr->u.sin6.sin6_port = port;
if (addr->u.sa.sa_family == AF_INET6) {
addr_len = sizeof(addr->u.sin6);
} else {
addr->u.sin.sin_port = port;
addr_len = sizeof(addr->u.sin);
}
@@ -1073,6 +1088,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
int rc;
int was_rtcp = 0;
struct osmo_sockaddr rtcp_addr;
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
@@ -1089,7 +1105,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
if (mgcp_conn_rtp_is_iuup(conn))
rc = mgcp_conn_iuup_send_dummy(conn);
else
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr, conn->end.rtp_port,
rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc == -1)
@@ -1099,8 +1115,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
return rc;
was_rtcp = 1;
rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
conn->end.rtcp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
rtcp_addr = conn->end.addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
rtp_dummy_payload, sizeof(rtp_dummy_payload));
if (rc >= 0)
return rc;
@@ -1146,17 +1164,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
else
LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
/* FIXME: It is legal that the payload type on the egress connection is
* different from the payload type that has been negotiated on the
* ingress connection. Essentially the codecs are the same so we can
* match them and patch the payload type. However, if we can not find
* the codec pendant (everything ist equal except the PT), we are of
* course unable to patch the payload type. A situation like this
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
if (is_rtp && conn_dst->type != MGCP_RTP_IUUP) {
/* Patch the payload type number: translate from conn_src to conn_dst.
* Do not patch for IuUP, where the correct payload type number is already set in bridge_iuup_to_rtp_peer():
* IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
* {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
rc = mgcp_patch_pt(conn_src, conn_dst, msg);
if (rc < 0) {
/* FIXME: It is legal that the payload type on the egress connection is
* different from the payload type that has been negotiated on the
* ingress connection. Essentially the codecs are the same so we can
* match them and patch the payload type. However, if we can not find
* the codec pendant (everything ist equal except the PT), we are of
* course unable to patch the payload type. A situation like this
* should not occur if transcoding is consequently avoided. Until
* we have transcoding support in osmo-mgw we can not resolve this. */
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"can not patch PT because no suitable egress codec was found.\n");
}
@@ -1180,7 +1202,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
} else if (is_rtp) {
int cont;
@@ -1203,12 +1225,13 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
/* the iuup code will correctly transform to the correct AMR mode */
} else if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
rc = amr_oa_bwe_convert(endp, msg,
conn_dst->end.codec->param.amr_octet_aligned);
if (rc < 0) {
LOGPENDP(endp, DRTP, LOGL_ERROR,
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
"Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
break;
}
} else if (rtp_end->rfc5993_hr_convert &&
@@ -1225,14 +1248,14 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
"rtp_port:%u rtcp_port:%u\n",
dest_name,
osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
);
/* Forward a copy of the RTP data to a debug ip/port */
forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
msg);
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
(char *)msgb_data(msg), msgb_length(msg));
if (len <= 0)
@@ -1247,15 +1270,17 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
} while (buflen > 0);
return nbytes;
} else if (!trunk->omit_rtcp) {
struct osmo_sockaddr rtcp_addr = rtp_end->addr;
osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
LOGPENDP(endp, DRTP, LOGL_DEBUG,
"send to %s %s rtp_port:%u rtcp_port:%u\n",
dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp_end->addr.u.sa),
osmo_sockaddr_port(&rtcp_addr.u.sa)
);
len = mgcp_udp_send(rtp_end->rtcp.fd,
&rtp_end->addr,
rtp_end->rtcp_port, (char *)msgb_data(msg), msgb_length(msg));
len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
(char *)msgb_data(msg), msgb_length(msg));
rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
@@ -1267,13 +1292,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
return 0;
}
/*! dispatch incoming RTP packet to opposite RTP connection.
* \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP).
* \param[in] addr socket address where the RTP packet has been received from.
* \param[in] buf buffer that hold the RTP payload.
* \param[in] buf_size size data length of buf.
* \param[in] conn originating connection.
* \returns 0 on success, -1 on ERROR. */
/*! Dispatch incoming RTP packet to opposite RTP connection.
* \param[in] msg Message buffer to bridge, coming from source connection.
* msg shall contain "struct osmo_rtp_msg_ctx *" attached in
* "OSMO_RTP_MSG_CTX(msg)".
* \returns 0 on success, -1 on ERROR.
*/
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
{
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
@@ -1302,25 +1326,15 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (conn->u.rtp.end.rtp_port == 0) {
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
switch (from_addr->u.sa.sa_family) {
case AF_INET:
conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
break;
case AF_INET6:
conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
break;
default:
OSMO_ASSERT(false);
}
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
conn->u.rtp.end.rtp_port);
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_send_rtp(conn_src, msg);
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
/* Find a destination connection. */
@@ -1352,7 +1366,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
}
/* Dispatch RTP packet to destination RTP connection */
return mgcp_send_rtp(&conn_dst->u.rtp, msg);
return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
}
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
@@ -1377,25 +1391,15 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
* packets back to their origin. We will use the originating
* address data from the UDP packet header to patch the
* outgoing address in connection on the fly */
if (conn->u.rtp.end.rtp_port == 0) {
if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
memcpy(&conn->u.rtp.end.addr, from_addr,
sizeof(conn->u.rtp.end.addr));
switch (from_addr->u.sa.sa_family) {
case AF_INET:
conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
break;
case AF_INET6:
conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
break;
default:
OSMO_ASSERT(false);
}
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"loopback mode: implicitly using source address (%s:%u) as destination address\n",
osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
conn->u.rtp.end.rtp_port);
osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
}
return mgcp_send_rtp(conn_src, msg);
return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
}
/* Forward to E1 */
@@ -1504,8 +1508,8 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
sizeof(struct sockaddr_in)));
/* Increment RX statistics */
rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_PACKETS_RX_CTR));
rate_ctr_add(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_OCTETS_RX_CTR), msgb_length(msg));
rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_PACKETS_RX_CTR));
rate_ctr_add(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_OCTETS_RX_CTR), msgb_length(msg));
/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
/* Forward a copy of the RTP data to a debug ip/port */
@@ -1529,25 +1533,30 @@ static int rx_rtp(struct msgb *msg)
LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
mgcp_conn_watchdog_kick(conn_src->conn);
/* If AMR is configured for the ingress connection a conversion of the
* framing mode (octet-aligned vs. bandwith-efficient is explicitly
* define, then we check if the incoming payload matches that
* expectation. */
if (mc->proto == MGCP_PROTO_RTP &&
amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
return -1;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
return -1;
}
/* Check if the origin of the RTP packet seems plausible */
if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
return -1;
/* If AMR is configured for the ingress connection and conversion of the
* framing mode (octet-aligned vs. bandwith-efficient) is explicitly
* defined, then we check if the incoming payload matches that
* expectation. */
if (mc->proto == MGCP_PROTO_RTP &&
mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
if (oa < 0)
return -1;
if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
LOG_CONN_RTP(conn_src, LOGL_NOTICE,
"rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
" check the config of your call-agent!\n",
msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
return -1;
}
}
mgcp_conn_watchdog_kick(conn_src->conn);
/* Execute endpoint specific implementation that handles the
* dispatching of the RTP data */
return conn->endp->type->dispatch_rtp_cb(msg);

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_iuup.h>
#include <osmocom/mgcp/debug.h>
/* Contains the last successfully resolved endpoint name. This variable is used
* for the unit-tests to verify that the endpoint was correctly resolved. */
@@ -150,8 +151,7 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
switch (conn->type) {
case MGCP_RTP_DEFAULT:
case MGCP_OSMUX_BSC:
case MGCP_OSMUX_BSC_NAT:
case MGCP_RTP_OSMUX:
case MGCP_RTP_IUUP:
break;
default:
@@ -301,7 +301,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
/* Attach optional OSMUX parameters */
if (mgcp_conn_rtp_is_osmux(conn)) {
rc = msgb_printf(sdp, "X-Osmux: %u\r\n", conn->osmux.cid);
rc = msgb_printf(sdp, MGCP_X_OSMO_OSMUX_HEADER " %u\r\n", conn->osmux.local_cid);
if (rc < 0)
goto error;
}
@@ -324,8 +324,13 @@ error:
* osmux connection, send the dummy packet via OSMUX */
static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
if (conn->osmux.state != OSMUX_STATE_DISABLED)
osmux_send_dummy(endp, conn);
/* Avoid sending dummy packet if the remote address was not yet
* configured through CRCX/MDCX: */
if (!mgcp_rtp_end_remote_addr_available(&conn->end))
return;
if (mgcp_conn_rtp_is_osmux(conn))
osmux_send_dummy(conn);
else
mgcp_send_dummy(endp, conn);
}
@@ -709,7 +714,7 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
"Configuring RTP endpoint: local port %d%s%s\n",
ntohs(rtp->rtp_port),
osmo_sockaddr_port(&rtp->addr.u.sa),
rtp->force_aligned_timing ? ", force constant timing" : "",
rtp->force_constant_ssrc ? ", force constant ssrc" : "");
}
@@ -740,12 +745,12 @@ uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
*/
static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
{
if (!endp->trunk->cfg->osmux_init) {
if (osmux_init(OSMUX_ROLE_BSC, endp->trunk->cfg) < 0) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
if (!endp->trunk->cfg->osmux.initialized) {
if (osmux_init(endp->trunk) < 0) {
LOGPENDP(endp, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
return -3;
}
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
LOGPENDP(endp, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
}
return mgcp_parse_osmux_cid(line);
@@ -846,7 +851,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
const char *callid = NULL;
const char *mode = NULL;
char *line;
int have_sdp = 0, osmux_cid = -2;
int have_sdp = 0, remote_osmux_cid = -2;
struct mgcp_conn_rtp *conn = NULL;
struct mgcp_conn *_conn = NULL;
char conn_name[512];
@@ -893,9 +898,9 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
case 'X':
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
/* If osmux is disabled, just skip setting it up */
if (!rq->endp->trunk->cfg->osmux)
if (rq->endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
break;
osmux_cid = mgcp_osmux_setup(endp, line);
remote_osmux_cid = mgcp_osmux_setup(endp, line);
break;
}
@@ -998,16 +1003,17 @@ mgcp_header_done:
goto error2;
}
/* Annotate Osmux circuit ID and set it to negotiating state until this
* is fully set up from the dummy load. */
conn->osmux.state = OSMUX_STATE_DISABLED;
if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
conn->osmux.state = OSMUX_STATE_ACTIVATING;
if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
/* If X-Osmux (remote CID) was received (-1 is wilcard), alloc next avail CID as local CID */
if (remote_osmux_cid >= -1) {
if (osmux_init_conn(conn) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
goto error2;
}
} else if (endp->trunk->cfg->osmux == OSMUX_USAGE_ONLY) {
if (remote_osmux_cid >= 0) {
conn->osmux.remote_cid_present = true;
conn->osmux.remote_cid = remote_osmux_cid;
}
} else if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_ONLY) {
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
"CRCX: osmux only and no osmux offered\n");
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
@@ -1054,7 +1060,7 @@ mgcp_header_done:
/* check connection mode setting */
if (conn->conn->mode != MGCP_CONN_LOOPBACK
&& conn->conn->mode != MGCP_CONN_RECV_ONLY
&& conn->end.rtp_port == 0) {
&& osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
"CRCX: selected connection mode type requires an opposite end!\n");
error_code = 527;
@@ -1064,7 +1070,10 @@ mgcp_header_done:
/* Find a local address for conn based on policy and initial SDP remote
information, then find a free port for it */
mgcp_get_local_addr(conn->end.local_addr, conn);
if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
}
if (allocate_port(endp, conn) != 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error2;
@@ -1077,13 +1086,20 @@ mgcp_header_done:
goto error2;
}
/* Notify Osmux conn that CRCX was received */
if (mgcp_conn_rtp_is_osmux(conn)) {
if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
goto error2;
}
}
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
"CRCX: Creating connection: port: %u\n", conn->end.local_port);
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
mgcp_rtp_end_remote_addr_available(&conn->end) &&
trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
send_dummy(endp, conn);
@@ -1118,7 +1134,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
const char *mode = NULL;
struct mgcp_conn_rtp *conn = NULL;
const char *conn_id = NULL;
int osmux_cid = -2;
int remote_osmux_cid = -2;
int rc;
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
@@ -1174,9 +1190,9 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
case 'X':
if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
/* If osmux is disabled, just skip setting it up */
if (!endp->trunk->cfg->osmux)
if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
break;
osmux_cid = mgcp_osmux_setup(endp, line);
remote_osmux_cid = mgcp_osmux_setup(endp, line);
break;
}
/* Ignore unknown X-headers */
@@ -1253,30 +1269,39 @@ mgcp_header_done:
}
if (mgcp_conn_rtp_is_osmux(conn)) {
OSMO_ASSERT(conn->osmux.cid_allocated);
if (osmux_cid < -1) {
OSMO_ASSERT(conn->osmux.local_cid_allocated);
if (remote_osmux_cid < -1) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: Failed to parse Osmux CID!\n");
goto error3;
} else if (osmux_cid == -1) {
} else if (remote_osmux_cid == -1) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: wilcard in MDCX is not supported!\n");
goto error3;
} else if (osmux_cid != (int) conn->osmux.cid) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: changing already allocated CID is not supported!\n");
goto error3;
} else if (conn->osmux.remote_cid_present &&
remote_osmux_cid != conn->osmux.remote_cid) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: changing already allocated CID is not supported!\n");
goto error3;
} else {
conn->osmux.remote_cid_present = true;
conn->osmux.remote_cid = remote_osmux_cid;
if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"MDCX: Osmux handling failed!\n");
goto error3;
}
}
/* TODO: In the future (when we have recvCID!=sendCID), we need to
tell Osmux code that osmux_cid is to be used as sendCID for
that conn. */
}
/* MDCX may have provided a new remote address, which means we may need
to update our announced IP addr and re-bind our local end. This can
happen for instance if MGW initially provided an IPv4 during CRCX
ACK, and now MDCX tells us the remote has an IPv6 address. */
mgcp_get_local_addr(new_local_addr, conn);
if (mgcp_get_local_addr(new_local_addr, conn) < 0) {
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
goto error3;
}
if (strcmp(new_local_addr, conn->end.local_addr)) {
osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
mgcp_free_rtp_port(&conn->end);
@@ -1300,7 +1325,6 @@ mgcp_header_done:
/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
mgcp_rtp_end_remote_addr_available(&conn->end) &&
trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
send_dummy(endp, conn);
@@ -1569,8 +1593,7 @@ static void mgcp_keepalive_timer_cb(void *_trunk)
struct mgcp_endpoint *endp = trunk->endpoints[i];
llist_for_each_entry(conn, &endp->conns, entry) {
if (conn->type == MGCP_CONN_TYPE_RTP &&
conn->mode == MGCP_CONN_RECV_ONLY &&
mgcp_rtp_end_remote_addr_available(&conn->u.rtp.end))
conn->mode == MGCP_CONN_RECV_ONLY)
send_dummy(endp, &conn->u.rtp);
}
}
@@ -1624,7 +1647,6 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->source_port = 2427;
osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr));
cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;

View File

@@ -43,7 +43,7 @@ static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
{ "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
};
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
.group_name_prefix = "mgcp",
.group_description = "mgcp general statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
@@ -71,7 +71,7 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
};
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
.group_name_prefix = "crcx",
.group_description = "crxc statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
@@ -97,7 +97,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
};
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
.group_name_prefix = "mdcx",
.group_description = "mdcx statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
@@ -116,7 +116,7 @@ static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
};
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
.group_name_prefix = "dlcx",
.group_description = "dlcx statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
@@ -130,7 +130,7 @@ static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
};
const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
.group_name_prefix = "e1",
.group_description = "e1 statistics",
.class_id = OSMO_STATS_CLASS_GLOBAL,
@@ -138,7 +138,7 @@ const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
.ctr_desc = e1_rate_ctr_desc
};
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
.group_name_prefix = "all_rtp_conn",
.group_description = "aggregated statistics for all rtp connections",
.class_id = 1,
@@ -146,6 +146,14 @@ const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
.ctr_desc = all_rtp_conn_rate_ctr_desc
};
static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
.group_name_prefix = "all_osmux_conn",
.group_description = "aggregated statistics for all osmux connections",
.class_id = 1,
.num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
.ctr_desc = all_osmux_conn_rate_ctr_desc
};
/*! allocate global rate counters
* (called once at startup).
* \param[in] cfg mgw configuration for which the rate counters are allocated.
@@ -191,6 +199,7 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
static atomic_uint mdcx_rate_ctr_index = 0;
static atomic_uint dlcx_rate_ctr_index = 0;
static atomic_uint all_rtp_conn_rate_ctr_index = 0;
static atomic_uint all_osmux_conn_rate_ctr_index = 0;
char ctr_name[256];
if (ratectr->mgcp_crcx_ctr_group == NULL) {
@@ -229,6 +238,15 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
}
if (ratectr->all_osmux_conn_stats == NULL) {
ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
all_osmux_conn_rate_ctr_index++);
if (!ratectr->all_osmux_conn_stats)
return -EINVAL;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
}
/* E1 specific */
if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
@@ -265,6 +283,10 @@ void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
rate_ctr_group_free(ratectr->all_rtp_conn_stats);
ratectr->all_rtp_conn_stats = NULL;
}
if (ratectr->all_osmux_conn_stats) {
rate_ctr_group_free(ratectr->all_osmux_conn_stats);
ratectr->all_osmux_conn_stats = NULL;
}
/* E1 specific */
if (ratectr->e1_stats) {

View File

@@ -384,7 +384,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
case 'm':
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
if (rc == 1) {
rtp->rtp_port = htons(port);
osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
rtp->rtcp_port = htons(port + 1);
}
@@ -432,7 +432,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
rtp->packet_duration_ms);
if (codecs_used == 0)
LOGPC(DLMGCP, LOGL_NOTICE, "none");
@@ -601,7 +601,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
payload_types[0] = payload_type;
if (mgcp_conn_rtp_is_osmux(conn))
local_port = endp->trunk->cfg->osmux_port;
local_port = endp->trunk->cfg->osmux.local_port;
else
local_port = conn->end.local_port;
rc = add_audio(sdp, payload_types, 1, local_port);

View File

@@ -39,7 +39,7 @@ __attribute__((no_sanitize("undefined")))
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
{
struct mgcp_rtp_state *state = &conn->state;
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
*expected = state->stats.cycles + state->stats.max_seq;
*expected = *expected - state->stats.base_seq + 1;
@@ -80,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
int ploss;
int nchars;
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
calc_loss(conn, &expected, &ploss);
jitter = calc_jitter(&conn->state);
@@ -99,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
str += nchars;
str_len -= nchars;
if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
if (conn->conn->endp->trunk->cfg->osmux.usage != OSMUX_USAGE_OFF) {
/* Error Counter */
nchars = snprintf(str, str_len,
"\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
@@ -112,9 +112,12 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
str_len -= nchars;
if (conn->osmux.state == OSMUX_STATE_ENABLED) {
struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
snprintf(str, str_len,
"\r\nX-Osmux-ST: CR=%u, BR=%u",
conn->osmux.stats.chunks, conn->osmux.stats.octets);
"\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
osmux_chunks_rx->current, osmux_octets_rx->current);
}
}

View File

@@ -129,7 +129,7 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
VTY_NEWLINE);
switch (g_cfg->osmux) {
switch (g_cfg->osmux.usage) {
case OSMUX_USAGE_ON:
vty_out(vty, " osmux on%s", VTY_NEWLINE);
break;
@@ -141,17 +141,23 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " osmux off%s", VTY_NEWLINE);
break;
}
if (g_cfg->osmux) {
vty_out(vty, " osmux bind-ip %s%s",
g_cfg->osmux_addr, VTY_NEWLINE);
if (g_cfg->osmux.usage != OSMUX_USAGE_OFF) {
if (g_cfg->osmux.local_addr_v4)
vty_out(vty, " osmux bind-ip %s%s",
g_cfg->osmux.local_addr_v4, VTY_NEWLINE);
if (g_cfg->osmux.local_addr_v6)
vty_out(vty, " osmux bind-ip-v6 %s%s",
g_cfg->osmux.local_addr_v6, VTY_NEWLINE);
vty_out(vty, " osmux batch-factor %d%s",
g_cfg->osmux_batch, VTY_NEWLINE);
g_cfg->osmux.batch_factor, VTY_NEWLINE);
vty_out(vty, " osmux batch-size %u%s",
g_cfg->osmux_batch_size, VTY_NEWLINE);
g_cfg->osmux.batch_size, VTY_NEWLINE);
vty_out(vty, " osmux port %u%s",
g_cfg->osmux_port, VTY_NEWLINE);
g_cfg->osmux.local_port, VTY_NEWLINE);
vty_out(vty, " osmux dummy %s%s",
g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
g_cfg->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
vty_out(vty, " osmux peer-behind-nat %s%s",
g_cfg->osmux.peer_behind_nat ? "on" : "off", VTY_NEWLINE);
}
if (g_cfg->conn_timeout)
@@ -169,11 +175,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
struct rate_ctr *rx_packets, *rx_bytes;
struct rate_ctr *dropped_packets;
tx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
tx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
rx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
rx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
dropped_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_DROPPED_PACKETS_CTR);
tx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
tx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
rx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
rx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
dropped_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_DROPPED_PACKETS_CTR);
vty_out(vty,
" Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
@@ -189,7 +195,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
rx_packets->current, rx_bytes->current, VTY_NEWLINE,
state->in_stream.err_ts_ctr->current,
state->out_stream.err_ts_ctr->current,
VTY_NEWLINE,
VTY_NEWLINE,
dropped_packets->current, VTY_NEWLINE,
codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
codec->frame_duration_num, codec->frame_duration_den,
@@ -197,6 +203,30 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
codec->subtype_name, VTY_NEWLINE, end->output_enabled,
end->force_output_ptime, VTY_NEWLINE);
if (mgcp_conn_rtp_is_osmux(conn)) {
struct rate_ctr *rx_chunks, *rx_octets, *rtp_tx, *rtp_tx_dropped, *octets_tx;
rx_chunks = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_CHUNKS_RX_CTR);
rx_octets = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_OCTETS_RX_CTR);
rtp_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_CTR);
rtp_tx_dropped = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
octets_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_AMR_OCTETS_TX_CTR);
vty_out(vty,
" Osmux:%s"
" State: %s%s"
" Local CID: %d%s"
" Remote CID: %d%s"
" Chunks received: %" PRIu64 " (%" PRIu64 " bytes total)%s"
" RTP Packets encoded (Tx): %" PRIu64 " (%" PRIu64 " AMR octets total)%s"
" AMR payloads Dropped (Tx): %" PRIu64 "%s",
VTY_NEWLINE, osmux_state_str(conn->osmux.state), VTY_NEWLINE,
conn->osmux.local_cid_allocated ? conn->osmux.local_cid : -1, VTY_NEWLINE,
conn->osmux.remote_cid_present ? conn->osmux.remote_cid : -1, VTY_NEWLINE,
rx_chunks->current, rx_octets->current, VTY_NEWLINE,
rtp_tx->current, octets_tx->current, VTY_NEWLINE,
rtp_tx_dropped->current, VTY_NEWLINE
);
}
}
static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
@@ -289,6 +319,14 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
" %25n: %10c (%S/s %M/m %H/h %D/d) %d",
ratectr->all_rtp_conn_stats);
}
if (ratectr->all_osmux_conn_stats) {
vty_out(vty, " %s:%s",
ratectr->all_osmux_conn_stats->desc->group_description,
VTY_NEWLINE);
vty_out_rate_ctr_group_fmt(vty,
" %25n: %10c (%S/s %M/m %H/h %D/d) %d",
ratectr->all_osmux_conn_stats);
}
if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
vty_out(vty, " %s:%s",
@@ -342,7 +380,7 @@ static int mgcp_show(struct vty *vty, int argc, const char **argv,
llist_for_each_entry(trunk, &g_cfg->trunks, entry)
dump_trunk(vty, trunk, show_stats, active_only);
if (g_cfg->osmux)
if (g_cfg->osmux.usage != OSMUX_USAGE_OFF)
vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
VTY_NEWLINE);
@@ -1539,12 +1577,12 @@ DEFUN(cfg_mgcp_osmux,
OSMO_ASSERT(trunk);
if (strcmp(argv[0], "off") == 0) {
g_cfg->osmux = OSMUX_USAGE_OFF;
g_cfg->osmux.usage = OSMUX_USAGE_OFF;
return CMD_SUCCESS;
} else if (strcmp(argv[0], "on") == 0)
g_cfg->osmux = OSMUX_USAGE_ON;
g_cfg->osmux.usage = OSMUX_USAGE_ON;
else if (strcmp(argv[0], "only") == 0)
g_cfg->osmux = OSMUX_USAGE_ONLY;
g_cfg->osmux.usage = OSMUX_USAGE_ONLY;
return CMD_SUCCESS;
@@ -1552,12 +1590,29 @@ DEFUN(cfg_mgcp_osmux,
DEFUN(cfg_mgcp_osmux_ip,
cfg_mgcp_osmux_ip_cmd,
"osmux bind-ip " VTY_IPV46_CMD,
"osmux bind-ip " VTY_IPV4_CMD,
OSMUX_STR IP_STR
"IPv4 Address to bind to\n")
{
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v4, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_osmux_ip_v6,
cfg_mgcp_osmux_ip_v6_cmd,
"osmux bind-ip-v6 " VTY_IPV6_CMD,
OSMUX_STR IP_STR
"IPv4 Address to bind to\n"
"IPv6 Address to bind to\n")
{
osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v6, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_osmux_port,
cfg_mgcp_osmux_port_cmd,
"osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
{
g_cfg->osmux.local_port = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -1566,7 +1621,7 @@ DEFUN(cfg_mgcp_osmux_batch_factor,
"osmux batch-factor <1-8>",
OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
{
g_cfg->osmux_batch = atoi(argv[0]);
g_cfg->osmux.batch_factor = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -1575,15 +1630,7 @@ DEFUN(cfg_mgcp_osmux_batch_size,
"osmux batch-size <1-65535>",
OSMUX_STR "batch size\n" "Batch size in bytes\n")
{
g_cfg->osmux_batch_size = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_osmux_port,
cfg_mgcp_osmux_port_cmd,
"osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
{
g_cfg->osmux_port = atoi(argv[0]);
g_cfg->osmux.batch_size = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -1594,9 +1641,24 @@ DEFUN(cfg_mgcp_osmux_dummy,
"Disable dummy padding\n")
{
if (strcmp(argv[0], "on") == 0)
g_cfg->osmux_dummy = 1;
g_cfg->osmux.dummy_padding = true;
else if (strcmp(argv[0], "off") == 0)
g_cfg->osmux_dummy = 0;
g_cfg->osmux.dummy_padding = false;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_osmux_peer_behind_nat,
cfg_mgcp_osmux_peer_behind_nat_cmd,
"osmux peer-behind-nat (on|off)",
OSMUX_STR "Define whether peer is behind NAT\n"
"Peer is behind NAT\n"
"Peer is NOT behind NAT\n")
{
if (strcmp(argv[0], "on") == 0)
g_cfg->osmux.peer_behind_nat = true;
else if (strcmp(argv[0], "off") == 0)
g_cfg->osmux.peer_behind_nat = false;
return CMD_SUCCESS;
}
@@ -1686,10 +1748,12 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
install_element(MGCP_NODE, &cfg_mgcp_osmux_peer_behind_nat_cmd);
install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
@@ -1734,9 +1798,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
int rc;
struct mgcp_trunk *trunk;
cfg->osmux_port = OSMUX_PORT;
cfg->osmux_batch = 4;
cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
cfg->osmux.local_port = OSMUX_DEFAULT_PORT;
cfg->osmux.batch_factor = 4;
cfg->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
g_cfg = cfg;
rc = vty_read_config_file(config_file, NULL);

View File

@@ -41,7 +41,6 @@
#include <osmocom/mgcp/debug.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_ctrl.h>
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
@@ -51,7 +50,7 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/socket.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_vty.h>
#include <osmocom/vty/telnet_interface.h>
@@ -95,7 +94,7 @@ static char *config_file = "osmo-mgw.cfg";
/* used by msgb and mgcp */
void *tall_mgw_ctx = NULL;
static void print_help()
static void print_help(void)
{
printf("Some useful options:\n");
printf(" -h --help is printing this text.\n");
@@ -295,13 +294,22 @@ static const struct log_info_cat log_categories[] = {
.name = "DRTP",
.description = "RTP stream handling",
.color = "\033[1;30m",
.enabled = 1,.loglevel = LOGL_NOTICE,
.enabled = 1,
.loglevel = LOGL_NOTICE,
},
[DE1] = {
.name = "DE1",
.description = "E1 line handling",
.color = "\033[1;31m",
.enabled = 1,.loglevel = LOGL_NOTICE,
.enabled = 1,
.loglevel = LOGL_NOTICE,
},
[DOSMUX] = {
.name = "DOSMUX",
.description = "Osmux (Osmocom RTP multiplexing)",
.color = "\033[1;32m",
.enabled = 1,
.loglevel = LOGL_NOTICE,
},
};
@@ -357,7 +365,7 @@ int main(int argc, char **argv)
if (rc < 0)
return rc;
cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
cfg->ctrl = ctrl_interface_setup(cfg, OSMO_CTRL_PORT_MGW, NULL);
if (!cfg->ctrl) {
fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);

View File

@@ -1071,7 +1071,7 @@ static void test_packet_loss_calc(void)
"test-connection");
conn = mgcp_conn_get_rtp(&endp, _conn->id);
state = &conn->state;
packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
state->stats.initialized = 1;
state->stats.base_seq = pl_test_dat[i].base_seq;
@@ -1492,7 +1492,7 @@ static void test_multilple_codec(void)
conn = mgcp_conn_get_rtp(endp, conn_id);
OSMO_ASSERT(conn);
OSMO_ASSERT(conn->end.codec->payload_type == 3);
OSMO_ASSERT(conn->end.rtp_port == htons(16434));
OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
memset(&addr, 0, sizeof(addr));
inet_aton("8.8.8.8", &addr);
OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
@@ -1632,7 +1632,8 @@ static void test_osmux_cid(void)
for (i = 0; i < 256; ++i) {
id = osmux_cid_pool_get_next();
OSMO_ASSERT(id == i);
/* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
OSMO_ASSERT(id == ((i + 1) & 0xff));
OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
}
@@ -2078,7 +2079,7 @@ static void test_mgcp_codec_pt_translate(void)
OSMO_ASSERT(ok);
}
void test_conn_id_matching()
void test_conn_id_matching(void)
{
struct mgcp_endpoint endp = {};
struct mgcp_conn *conn;
@@ -2118,7 +2119,7 @@ void test_conn_id_matching()
talloc_free(conn);
}
void test_e1_trunk_nr_from_epname()
void test_e1_trunk_nr_from_epname(void)
{
unsigned int trunk_nr;
int rc;
@@ -2168,7 +2169,7 @@ void test_e1_trunk_nr_from_epname()
return;
}
void test_mgcp_is_rtp_dummy_payload()
void test_mgcp_is_rtp_dummy_payload(void)
{
/* realistic rtp packet */
static const char rtp_payload[] =

View File

@@ -315,7 +315,7 @@ void test_mgcp_msg(void)
msgb_free(msg);
}
void test_mgcp_client_cancel()
void test_mgcp_client_cancel(void)
{
mgcp_trans_id_t trans_id;
struct msgb *msg;
@@ -487,7 +487,7 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
},
};
void test_sdp_section_start()
void test_sdp_section_start(void)
{
int i;
int failures = 0;