Compare commits

..

164 Commits

Author SHA1 Message Date
Oliver Smith
46ab31c377 Bump version: 1.9.1.1-6c87a → 1.9.2
Change-Id: Icae11e2065545904163882dd2c650ff670425c15
2023-05-26 14:57:36 +02:00
Oliver Smith
6c87ac9af3 systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: Ib6c78c76c5f13b9482428ce653a61b03b2aca1d3
2023-05-26 14:57:18 +02:00
Harald Welte
23c623b487 Bump version: 1.9.0.1-1a099 → 1.9.1
Change-Id: I8801d482858f4c9f44f9d320e4393e8fab43b58f
2022-04-18 10:58:50 +02:00
Vadim Yanitskiy
1a099fd34c libosmo-mgcp: e1: fix memleaks in e1_recv_cb()
Change-Id: I4be9e6d09b34e792f24c9f09d19dce15b9dfbe3f
Fixes: OS#5533
2022-04-18 10:57:08 +02:00
Pau Espin Pedrol
58dc88bc31 Bump version: 1.8.1.90-aac8-dirty → 1.9.0
Change-Id: Icfc615c0d7d826269962b0d94fbe53c2f8adfdaf
2021-11-16 16:59:21 +01:00
Eric
aac84edc9d fix up some docstrings that lost their dot
Change-Id: I88333c165f1dc11ae29f4c1726c15656386d1f0e
2021-11-09 18:45:09 +01:00
Oliver Smith
172f5acfce Revert "Turn some compiler warnings into errors"
Do not turn some compiler warnings into errors by default. This patch
was added before --enable-werror was available.

We build with --enable-werror during development and in CI. If the code
is built with a different compiler that throws additional warnings, it
should not stop the build.

This reverts commit 34f012639d.

Related: OS#5289
Change-Id: I6042f917a5a891dd13cb96d9477a45a45a7b35fe
2021-11-04 10:52:40 +01:00
Eric
fdbefde869 fix mgcp_conn_free_all
It calls itself recursively which messes with the list an ep, so ubsan
complains.

Change-Id: If38ead0ba0c28396df2332990c98b2532cf17d1c
2021-11-03 15:19:13 +00:00
Eric
25ecc91c3b rename strip_epname and find_specific_endpoint and make them available
Change-Id: I4f76676640a308ab84da3848e1c1ec22bd5d9566
2021-11-03 15:19:13 +00:00
Eric
995529548b add modified .clang-format
Adjusted ColumnLimit: 80 -> 120
Added ForEachMacros:
  - 'for_each_line'
  - 'for_each_non_empty_line'

Change-Id: I080cf2d2437d0b8e6190fbd7c01af8cdc9420878
2021-11-03 15:18:45 +00:00
Vadim Yanitskiy
0c04500ac5 libosmo-mgcp: use OSMO_STRLCPY_ARRAY in mgcp_codec_add()
Change-Id: Icc2486308577b587a6ebd1b44b2fa92693aa7fc7
Fixes: CID#240100
2021-10-21 00:07:02 +03:00
Pau Espin Pedrol
a0b69f1896 Fix attribute parsing on gcc 11.1.0
Fixes following compilation error:
"osmo-mgw/src/libosmo-mgcp/mgcp_stat.c:39:1: error: ‘integer’ attribute directive ignored"

Change-Id: Ia5167068abe8a22cd35a833396cbd7cb531c7e83
Fixes: f936e10f07
2021-09-20 10:00:50 +00:00
Eric
fbf78d13f1 endp: do not cache cfg pointer
There is no obvious reason why we would want to complicate the code by
caching pointers, since pointer traversal is probably not a performance
bottleneck, and if it is we should rather take a look at our dozens of
linked lists first..

Change-Id: I2456ba63598f76200d53e00223abf60bb36a49c0
2021-09-14 18:33:24 +02:00
Philipp Maier
df9192efee mgcp_client: add MGW name as logging context
Usually only one MGCP client per application is present. Then the log
lines from mgcp_client.c will be distinguishable without additional
information. When the application is using a pool of MGWs, then the
various MGCP Client instances become hard to distinguish.

- Add a possibility to set a description (name) for each MGW pool
  member. When no description is set, use the domain name.

- Output the pool member name on each log line in mgcp_client.c
  and mgcp_client_pool.c

Change-Id: I53ff5445c8e5faffa4ef908ffb1fdb1f47ea2904
Related: SYS#5091
2021-09-14 07:01:04 +00:00
Eric
70a658a2ba adjust talloc context
there is no obvious reason why the endpoints that belong to a trunk would
have the (global) config as parent context, you can't really have endpoints
without a trunk anyway.

Change-Id: Id3d5fefc12b7d442c09c507b3a8b0231e46e3068
2021-09-13 18:49:49 +02:00
Eric
2764bdb1aa embed strings into structs
They are mostly not even as large as the talloc header used to
dynamically allocate them, and they are also not "shared" by anything.

Change-Id: I7b46d531c5d3b53984f2ce44538116973f6a074d
2021-09-13 18:49:49 +02:00
Eric
55fdfc223e globally lock the portrange when trying to grab a port to prep for multithreading
Change-Id: I78ae737b829bb428372f34db7d5bc601b5088b78
2021-09-13 18:49:49 +02:00
Eric
8f33303660 libosmo-mgcp: do not use the default msgb talloc context
Trunk is safe, since it will not disappear sooner than the endpoints or
connections.

osmux still missing!

Change-Id: I15b01085f31e9a10a1ad381713ca2275356ca20c
2021-09-13 18:49:49 +02:00
Eric
a94c56e4c6 libosmo-mgcp: atomic rate counter group indexes
Postfix++ on atomics is specified as rmw operation with
memory_order_seq_cst.

Change-Id: Ib82d15aab2b3ba25827f9cf8751dbf87ee92a444
2021-09-13 18:49:49 +02:00
Eric
2ebcf5c34a libosmo-mgcp: cleanup audio codex alloc
No need to complicate audio codes with pointers, our "usual" string is
barely larger than a poointer, five times smaller than a talloc header,
and most importantly not really optional anyway...

Change-Id: Icc41643050a5e1ca3c66f307d60b6911ba1b8032
2021-09-13 18:49:49 +02:00
Eric
f936e10f07 stats: make sanitizers happy
The test expects wrapping here, but the undefined sanitizer is not happy
with that, so disable it.

Change-Id: I59ec65519ea028d4628ba4b56c939aef70794abf
2021-09-13 18:49:38 +02:00
Eric
e303fa9ff3 mgcp_sdp: fix potential leak
Change-Id: I31527b54f602634024a0b687eef26a9b29354282
2021-09-10 17:24:45 +02:00
Eric
958f5e74cc rename do_retransmission
...because it does not "do"

Change-Id: I5513e0ad15db4a0629f4e0348fc3e84d9972259a
2021-09-10 17:24:45 +02:00
Eric
1e8d5fa44b fix missing includes and forward declarations
Change-Id: I669e475f7ab74abef85f0f6194cc37db04af62e3
2021-09-10 17:24:45 +02:00
Eric
374ad788d8 configure.ac: fix maybe-uninitialized for clang
Clang and gcc have different names for this, but the check fails without
-Werror since clang only warns about unknown args.

The previous check led to a lot of "unknown arg" spam while compiling
with clang.

Change-Id: Iad6c16beed26d5fe8952d7d5a79a93845c391b48
2021-09-10 17:24:45 +02:00
Eric
da07b90f0f add vscode stuff to gitignore
Change-Id: If3cfb71700929aa63df7f4f7f89f5392ba94c77e
2021-09-09 16:04:17 +02:00
Philipp Maier
fa495d669f mgcp_client: fix typo in doxygen comment
Change-Id: I4431502ebbaa980f2abfdb98acba0f55ca658292
2021-09-02 10:09:28 +02:00
Philipp Maier
439c86fc58 mgcp_ratectr: remove unusued rate counters
The change I19f67db1c56473f47338b56114f6bbae8981d067 removes the
policy_cb and change_cb callback funtions, but it does not remove
the related ratecounters.

Change-Id: I53aa3c890555055466e86b09a359375a10d3be7b
2021-08-23 15:32:49 +02:00
Philipp Maier
74e83d3d82 mgcp_client_vty: fixing docstring
The docstring in the VTY command that is used to remove MGCP client
instances lacks the NO_STR constant.

Change-Id: I53f3e763a77ed8be78c5a51b1472f4b70bade9d4
Related: SYS#5091
2021-08-20 09:58:46 +02:00
Philipp Maier
d55be05af1 mgcp_client_vty: cosmetic: doc string should terminated with \n
Change-Id: I34c16490e08af0c9853f1a794113c191bb65d09a
2021-08-19 14:58:31 +02:00
Philipp Maier
8f91a7f450 mgcp_client_vty: fix docstrings for mgw-pool
The interactive VTY commands to reconnect, block and unblock MGCP
clients from the pool are not displayed properly because the doctring
lacks the reference number.

Change-Id: I0367c33f5cd02978e3f14b1343dfaafa1ea62370
Related: SYS#5091
2021-08-19 14:57:28 +02:00
Philipp Maier
da3a5759e1 mgcp_client_vty: add OSMO_ASSERT on pool parameter
When the function mgcp_client_pool_vty_init is called with pool = NULL,
then it segfaults. Lets put an OSMO_ASSERT() on pool to make clear that
a pool must be present before initalizing the VTY on it.

Change-Id: I36893bf5341d4ad21161e92d2d25d284647f7d18
2021-08-19 14:26:02 +02:00
Oliver Smith
29e671f257 mgcp_client_vty: add missing NO_STR
Fixes: 3f2c15 ("mgcp_client: allow to reset endpoints on startup")
Change-Id: Ib2052dcfcfc26fa898e31ffee1e792856fab22ed
2021-08-18 08:44:47 +02:00
Philipp Maier
d6a7e17911 mgcp_client_vty: add missing docstrings
The VTY for the classic non pooled MGCP Client does not have any API
doctumentation.

Change-Id: Ia7ca2e4a8efa714f7a56ffd18de152c992936221
2021-08-16 16:22:31 +02:00
Philipp Maier
3f4a4cb49c libosmo-mgcp-client: extend the mgcp_client for MGW pooling
At the moment the MGCP Client only supports one MGW per application.
Depending on the requirements of the application one MGW might not offer
the performance needed. Lets add support for an MGCP Client pool that is
backward compatible to existing applications.

Change-Id: Icaaba0e470e916eefddfee750b83f5f65291a6b0
Related: SYS#5091
2021-08-16 16:22:31 +02:00
Philipp Maier
3d2b76fd95 mgcp_client: refactor function init_socket
The function init_socket has an arbitrary retry count when opening the
socket. After each retry the local port is incremented by one. The
intention behind this is to find a useable local port in case the
configured port is used by another process.

The maximum number of retrys is hardcoded. The upcomming MGW pooling
patch requires to set the maximum retry count.

Change-Id: Ifd65511daa92fbe610f52da1c4c3b6a7c761d890
Related: SYS#5091
2021-08-16 16:22:31 +02:00
Philipp Maier
276a414aa3 mgcp_client: do not print (null) when address is ANY
When the address is set to ANY, the address string is NULL. The log then
prints "(null)" where the address normaly would be. This looks odd, lets
print "(any)" instead.

Change-Id: I2ea138827ee5b9f40d352bf594364ee930520609
2021-08-16 16:22:31 +02:00
Philipp Maier
c534ad17dc mgcp_client_vty: remove unnecessary checks
The vty always checks if global_mgcp_client_conf exists. (there is also
an assert This check about global_mgcp_client_ctx).
global_mgcp_client_ctx and global_mgcp_client_conf are populated before
the VTY commands are installed. Unleass the caller uses the API wrong
and calls mgcp_client_vty_init with NULL pointers there cannot be a
problem with unpopulated pointers. Lets remove the checks as they are
not needed.

Change-Id: I892d14c588573f76640453cb9c194594289b59f1
Related: SYS#5091
2021-08-16 16:22:31 +02:00
Philipp Maier
3f2c15f275 mgcp_client: allow to reset endpoints on startup
Depending on the usecase of osmo_mpcg_client it may be helpful to send a
DLCX to certain endpoints. Usually this would be a wildcarded endpoint
that resets the entire trunk to drop lingering RTP flows which may still
present after a restart/crash, but it might be also a group of specific
endpoints. The user may specify an arbitrary amount of endpoints where
the mgcp client will send a DLCX to. It does not matter if the endpoints
are wildcarded or not.

Change-Id: I47e7ff858d5067b46d52329be5f362ff61c0dff8
Related: SYS#5535
2021-08-16 16:22:31 +02:00
Philipp Maier
38533ba9b3 mgcp_ratectr: do not set talloc destructor on library allocated item
The rate counter and stats item groups, which are allocated in
mgcp_ratectr.c are freed using a talloc destructor that is set in the
context of the item we just allocated using the stats / rate counter API
functions. When we do that, we risk overwriting an already existing
talloc destructor. Lets instead implement own free functions and set
those as talloc_destructor from above (trunk and MGCP config)

Change-Id: Ifc5091e9f95cc721e58d1eb2e55b97102c497706
Related: OS#5201
2021-08-09 14:12:51 +02:00
Philipp Maier
39889e4389 mgcp_protocol: get rid of policy_cb and change_cb
The two callback functions policy_cb and change_cb are essentially dead
code. They also make the code more difficult to read and understand.
Lets remove them.

Change-Id: I19f67db1c56473f47338b56114f6bbae8981d067
2021-08-05 10:00:59 +02:00
Philipp Maier
c824fe4eb0 mgcp_client: fix typo Initalize -> Initialize
Change-Id: If57f8c0e54dbb5d37f40e36d968a6e6b75eec066
2021-08-04 08:04:10 +00:00
Philipp Maier
124a3e0b34 mgcp_ratectr: add stats items to monitor trunk usage
We are currently counting events in rate counters, but there is
currently no way to get a sample of the current situation of the trunk
usage. In particular how many endpoints are currently in use.

This is a corrected version of:
Ib7b654168dc3512f55e45cc4755dc1f6f423d023

Change-Id: I6d3a74f6087512130d85002348787bffc672de81
Related: SYS#5201
2021-08-03 15:05:46 +00:00
Philipp Maier
96c6e06681 mgcp_trunk: check MGW domain name earlier
The MGW domain name is usually checked while resolving the endpoint
after the trunk has been resolved. This was no problem before, but since
we allow wildcarded DLCX requests, which require only a trunk to work,
the check is not done correctly for wildcarded DLCX requests and invalid
domain names may slip through.

Checking the domain name earlier while the trunk is resolved makes sense
and it fixes the problem.

Change-Id: I9944a9103981fb5f4d0d8714ee2847ae020f76df
2021-07-29 15:31:57 +02:00
Philipp Maier
ce18705875 mgcp_protocol: assert endp when it becomes mandatory
The logic when an endp pointer is guranteed and when we are able to
process the request without the endp pointer populated is qute complex.
This shows up as a bug to coverity.

Change-Id: I1d4221f2df13c43321d5466534485cf21f0d9010
Fixes: CID#237088
2021-07-27 08:44:33 +00:00
Daniel Willmann
41ab87f67c contrib/jenkins: Use ASAN for osmo-mgw
Change-Id: I55cfea8a94730ebfaed1ef3227c50777edfb94fb
Related: OS#5201
2021-07-23 15:20:59 +02:00
Philipp Maier
a8739fc7be mgcp_lient: remove unsubstantial FIXME note
Change-Id: Ibc73a8a95d93c4a0f8a891bfba6fd1293ae6f1b5
2021-07-22 13:46:43 +00:00
Philipp Maier
21dfeff8aa remove struct member wildcarded_req from struct mgcp_endpoint
The struct member bool wildcarded_req is no longer needed

Change-Id: Iabd2df8f0f8fcce964af647e3a6d8e4c3006ab29
Related: SYS#5535
2021-07-22 13:34:42 +00:00
Philipp Maier
f486e741a4 mgcp_protocol: add support for wildcarded DLCX
The request handler handle_delete_con currently rejects wildcarded DLCX
requests even though a wildcarded DLCX would be a valuable tool to
remove lingering connections from the trunk in case osmo-bsc has to be
restarted.

Change-Id: I5c2de6b2b61ee64ba9c0618fd20e8fc2fe6a5ed3
Related: SYS#5535
2021-07-22 13:33:58 +00:00
neels
268568593e Revert "mgcp_ratectr: add stats items to monitor trunk usage"
This reverts commit 6bad138c96.

Reason for revert: heap-use-after-free during 'make check'
in mgcp_test.c test_retransmission()

Change-Id: I96792a719c9c7273676ab9ffe0b9e2aae4c23166
Related: OS#5201
2021-07-21 17:07:14 +00:00
Philipp Maier
41d59205c0 mgcp_protocol: refactor function create_response_with_sdp
The function create_response_with_sdp calls add_params, which is rather short.
The code in there can also be put in create_response_with_sdp. The
decision whether the endpoint name (Z) should be added or not, should be
made by the caller.

Change-Id: I7e29c513f4386832646e96194ed6c2397405ed3b
Related: SYS#5535
2021-07-21 11:16:36 +02:00
Philipp Maier
036612b035 mgcp_msg: add trunk parameter to mgcp_check_param for logging
There is not always an endp pointer present when mgcp_check_param() is
called but we always have a trunk pointer. Lets add a trunk parameter so
that the function can pick LOGPTRUNK when endp is not available.

Change-Id: I7327c5a105e7f0e20cabf64623ff9f36fd83bbb8
Related: SYS#5535
2021-07-21 11:16:36 +02:00
Philipp Maier
6bad138c96 mgcp_ratectr: add stats items to monitor trunk usage
We are currently counting events in rate counters, but there is
currently no way to get a sample of the current situation of the trunk
usage. In particular how many endpoints are currently in use.

Change-Id: Ib7b654168dc3512f55e45cc4755dc1f6f423d023
Related: SYS#5535
2021-07-20 17:00:09 +02:00
Philipp Maier
8dc3597085 mgcp_protocol: refactor MGCP request handling
At the moment the MGCP request handling and message parsing is not
clearly separated. The function mgcp_parse_header() in mgcp_msg.c is
also responsible for resolving an endpoint. This leads to unclear layer
separation. We eventually end up in a situation where we can not execute
any request handler without beeing able to resolve an endpoint, however
this is necessary if we want to implement wildcarded DLCX resquests.

In the current situation a wildcarded DLCX is not possible to implement
as we always have to resolve a an to get to the trunk which we need to
iterate. However, we just can't resolve a free endpoint in a situation
where all endpoints on te trunk are in use.

We have to refactor the request handler so that the parsing in mgcp_msg
only extracts us the endpoint name. The resolving is then done in
mgcp_handle_message() in mgcp_protocol.c. Then we are able to decide
what to do if we are unable to resolve an endpoint but still be able to
resolve the trunk.

This patch does not change the behaviour of osmo-mgw yet, but it lays
the foundation for request handler implementations that can still
perform useful actions if no endpoint but a trunk has been resolved. A
wilcarded DLCX is such a case. It does not need an endpoint, just the
trunk.

Change-Id: I9f519d8a0ee8a513fa1e74acf3ee7dbc0991cdde
Related: SYS#5535
2021-07-20 17:00:09 +02:00
Philipp Maier
d70eef6421 mgcp_trunk: use unsigned int instead of int as trunk_nr
the trunk_nr is in struct mgcp_trunk. The trunk number can not be
negative and there is no magic value that makes use of the fact that it
could be negative. Lets use unsigned int to make this less irretating.

Change-Id: I5d0e1d76adb8c92d84331a0aca2496908e41d621
Related: SYS#5535
2021-07-20 16:34:50 +02:00
Philipp Maier
33d97f721d mgcp_protocol: refactor request handler array
the various types of MGCP requests are implemented in request handlers
functions. The function pointers to those functions are held in an array
that is used to find the right handler and call it then. The struct used
to model the array is defined somewhat away from the array definition
and there is also a macro in between that does not help to make the code
more understandable. Lets refactor this a bit to have it more distinct.

Change-Id: I2ef167b2ac179d2b0683a27a095f9662fda460bf
Related: SYS#5535
2021-07-19 09:03:05 +00:00
Neels Hofmeyr
d57310731f mgcp_client: add logging on received MGCP messages
There is verbose debug logging on MGCP messages sent out to the MGW, but
none on received MGCP messages. Add Rx logging.

Related: SYS#5529
Change-Id: Id76230896aa87c1a12bd5ad87a62430c048a2873
2021-07-15 11:36:15 +02:00
Neels Hofmeyr
a8c684b51f mgcp_client_fsm: add missing log_subsys
To see state transitions and events on LMGCP DEBUG logging, actually set
the log_subsys of the mgcp_client_fsm.

Related: SYS#5529
Change-Id: I6e84d5f7b85752a7a54f17be1d074b01d1467f26
2021-07-15 02:28:03 +02:00
Neels Hofmeyr
03fcc91aad mgcp_client_endpoint_fsm: on term, still let conns wait for DLCX OK
When the mgcp_client_endpoint_fsm terminates, do not directly pull each
conn FSM instance (mgcp_client_fsm) into oblivion as well. Those should
emit a DLCX and wait for the "OK" response before deallocating.

In programs using the mgcp client endpoint FSM (osmo-bsc, osmo-msc),
this gets rid of false LMGCP ERROR logging related to DLCX like this:

  Cannot find matching MGCP transaction for trans_id 71998

Related: SYS#5529
Change-Id: I8fbfec5533e9be9cc7ea550df1e6639a0a215973
2021-07-15 02:28:03 +02:00
Neels Hofmeyr
9de30e7cc4 mgcp_client_fsm delete: set mgcp_client as ctx, not NULL
Upon mgcp_conn_delete(), we unparent the FSM instance. Instead of
setting the talloc ctx to NULL, place the deleting conn under the
struct mgcp_client talloc ctx.

Related: SYS#5529
Change-Id: Ia12749e0d7d520f24a967c2df9a4651267e1019e
2021-07-15 02:26:56 +02:00
Philipp Maier
d64c041cdb mgcp_endp: make wildcarded detection separate
osmo-mgw currently does only a very simple detection method for
wildcarded requests, but it makes sense to split this detection
off into a separate function so that it can be used from different code
locations and we still have it at one place only.

Change-Id: I27018c01afb8acabfcf5d435c996cc9806e52d6b
Related: SYS#5535
2021-07-14 15:15:15 +02:00
Philipp Maier
d02716d6c2 mgcp_protocol: forward declare mgcp_endpoint
The function mgcp_rtp_end_config() takes an mgcp_endpoint as
parameter. The header file does not declare the mgcp_endp struct
and it also does not include mgcp_endp.h because that also would
cause problems. Since the endp parameter in mgcp_rtp_end_config()
is only a pointer we can simply forward declare it.

This patch will currently not change anythig, but it will prevent
compiler warnings when we remove the endp pointer from
struct mgcp_parse_data in a follow up patch

Related: SYS#5535
Change-Id: I07a4d6f9d5334b1f4cf4b262482b8a67b1384398
2021-07-14 15:15:15 +02:00
Philipp Maier
a065e632c0 mgcp_ratectr: refactor rate counter and set group name
The rate counter group is currently only referenced by an index. In a
system with multiple trunks this makes it difficult to say which rate
counter group belongs to which trunk sinde the index that is used does
not necessarly corespond to a specific trunk.

Since rate counter groups can now get a human readable name assigned, we
should do that.

Also E1 specific rate counters only make sense for E1-trunks, so they
should not be present on the virtual trunk.

Change-Id: I5e7f0e9081a06af48e284afa5c36a095b2847704
2021-07-13 14:58:07 +02:00
Philipp Maier
bd060c3c99 mgcp_trunk: add value string for trunk type.
Change-Id: I634fb2a03744117e976430468ab5c57d50ab0089
2021-07-09 13:57:32 +02:00
Philipp Maier
97cae477fb mgcp_ratectr: fix sourcecode formatting
Change-Id: I7460fd4cdf1a552bca1af681faaa9bd8f88f1404
2021-07-09 13:57:32 +02:00
Philipp Maier
02c880a7dd mgcp_ratectr: drop ws line
Change-Id: Ib0bb231ebf1d941dee85bdea596f07fe26510ce5
2021-07-09 13:57:32 +02:00
Philipp Maier
ba09687768 mgcp_trunk: drop ws line
Change-Id: Iac2dfe5643d87066490a77211f01ee9ee3d9fcc7
2021-07-09 13:57:32 +02:00
Neels Hofmeyr
a4b677c45a check_rtp_destin(): clarify log msg
The braces as put before this patch would read as {"is known", "is not
yet known"}, which is confusing the actual situation.

Change-Id: Icd1f22a9f4147a2758c2f068ecba46cf7f732604
2021-07-09 11:52:04 +00:00
Philipp Maier
6b7afe8f57 mgw_main: fix loop that resets all endpoints
The loop that resets all endpoints in read_call_agent() starts counting
at endpoint index 1, but it should begin counting at index 0

Change-Id: I82a385e547e54d82eff95213652317ed2fdaadd8
2021-07-09 11:51:00 +00:00
Philipp Maier
4131a65c4d mgcp_protocol: fix loop that sends dummy RTP packets
The logic in mgcp_keepalive_timer_cb() only sends dummy packets for
endpoints 1-N, leaving out endpoint 0, this is not correct it should
include all endpoints (0-N).

Change-Id: I99a9b572eac26780bc1286a8dd63c4c5652fda4f
2021-07-09 11:51:00 +00:00
Pau Espin Pedrol
6a5e5ac2d4 Use DLMGCP instead of DLGLOBAL in log lines
Change-Id: I95e11e8b1803153315750840ecec01402becf819
2021-07-08 18:13:46 +02:00
Pau Espin Pedrol
b066bd0c86 Take into account Marker bit when patching RTP stream
On a deployed osmo-mgw with RTP traffic coming from a thirdparty
RTP source, it was usual to see log messages like following one from
time to time:
"The input timestamp has an alignment error of 159 on SSRC"

Doing a quick traffic analysis showed that the above mentioned RTP
source was generating traffic from time to time containing RTP packets
with the Marker (M) bit.

Those messages were logged because the verification & patching funcions
in osmo-mgw were not Marker-bit aware. Hence, this patch implements
support for Marker bit when handling RTP packets.

The Marker bit is usually used as a start of a talkspurt, and has to be
considered a syncrhonization point, where timestamp and relation to real
time don't need to match with last received RTP packet in the stream.

Related: SYS#5498
Change-Id: I1fb449eda49e82607649122b9b9d983a9e5983fa
2021-07-08 10:18:15 +00:00
Pau Espin Pedrol
d6769ea207 Fail rx MDCX sendrecv with invalid remote addr
use the recently new available API to check both remote address and
port, instead of only the port.
It doesn't make sense to configure a conn as sendrecv if we have no IP
address to send stuff to, similar to what was already being checked with
the port.

Change-Id: I6ce8cf52930d423d3db8c27251be8350a26a4ede
2021-07-07 14:12:35 +00:00
Pau Espin Pedrol
ca280a1a84 mgw: rx CRCX: Avoid sending dummy rtp if remote address not provided
The following sequence of events was seen frequently in a osmo-mgw
instance running on the field with heavy traffic:
"""
endpoint:rtpbridge/1@mgw CRCX: creating new connection ...
mgcp_network.c:236 endpoint:rtpbridge/1@mgw CI:1C8CCFA9 Failed to send dummy RTP packet.
"""

Allegedly, that happens because at CRCX time the remote address may
still not be known, hence we end up trying to send a dummy rtp packet
to, for instance, host 0.0.0.0 port 0, which will of course fail.
Let's avoid sending it if the address is not yet known.

Similary, same issue could be seen during MDCX, since at MDCX we don't
necessarily need to have a valid addr+port (there could be several MDCX
and only last one set it).

Finally, the keepalive timer also needs the check, since it iterates
over all connections, and it could be that some is still not fully
configured.

Related: SYS#5498
Change-Id: I8ceafda691146823b12232b4a804b4ce74acbdc8
2021-07-07 14:12:35 +00:00
Pau Espin Pedrol
a24dcc61d7 mgcp_send_dummy: Check RTP destination is available before attempt tx
Several log messages showing "Failed to send dummy RTP packet." were
seen in a osmo-mgw on the field. Let's re-use the function to check and
provide more information on what's wrong to ease debugging.

Related: SYS#5498
Change-Id: Iee6ac1f4d24c131e3bf40c37e6fdc252e5208ec8
2021-07-07 14:12:35 +00:00
Pau Espin Pedrol
62d9df684f mgcp_network.c: Reorder some functions in file
This is a preparation for next commit, where one of the function will
require an static function available before it in the file.

Moving the functions also make sense, in order to have the 3 mgcp send
functions together for more easy understanding.

This commit does small style changes to fix followint linter errors:
"""
src/libosmo-mgcp/mgcp_network.c:1036: ERROR:SPACING: space required after that ',' (ctx:VxV)
src/libosmo-mgcp/mgcp_network.c:1091: WARNING:BRACES: braces {} are not necessary for any arm of this statement
src/libosmo-mgcp/mgcp_network.c:1145: ERROR:POINTER_LOCATION: "(foo*)" should be "(foo *)"
src/libosmo-mgcp/mgcp_network.c:1163: ERROR:ELSE_AFTER_BRACE: else should follow close brace '}'
src/libosmo-mgcp/mgcp_network.c:1204: ERROR:POINTER_LOCATION: "(foo*)" should be "(foo *)"
src/libosmo-mgcp/mgcp_network.c:1226: ERROR:POINTER_LOCATION: "(foo*)" should be "(foo *)"
"""

Change-Id: Iff8dab942182a0d909519acddb86be75d9cda7ae
2021-07-07 14:12:35 +00:00
Pau Espin Pedrol
8358c4ba07 constify some function arg pointers
Change-Id: I7a7560fad96719da01f1ee30eea0be0e52c60e99
2021-07-07 13:44:39 +02:00
Pau Espin Pedrol
4c77e9b748 Define patch_ssrc as bool type
This variable clearly holds a boolean value, so let's use stdef to make
it clear.

Change-Id: I05233a413b0d8511d056e8f93467a111c4bdf119
2021-07-07 12:18:43 +02:00
Pau Espin Pedrol
33347a4f5d constify arg in addr_is_any()
Change-Id: Ie8cb750d2e265bae48bbfa8ea1d88f3e316879ed
2021-07-06 20:04:23 +02:00
Philipp Maier
7d86d4c523 mgcp_client: fix error handling in mgcp message generation
The functions add_lco and add_sdp assert when the codec string can not
be generated. This is the case when an unexpected codec is addressed in
the input parameter mgcp_msg for mgcp_msg_gen(). Even though the API
user is expected only to use the codec identifiers in mgcp_client.h the
check should not be done with an assert. Instead mgcp_msg_gen() should
just return NULL imediately.

Also all generation functions should not use magic numbers as return
codes. Instead constants from errno.h should be used. It is also
problematic that the return codes from msgb_printf are added up.
Depending. It makes more sense to use an OR operator since msgb_printf
only returns 0 or -EINVAL, so the end result will be -EINVAL if one or
more msgb_printf fail and not just a random negative value.

Change-Id: Ibb788343e0bec9c0eaf33e6e4727d4d36c100017
Related: OS#5119
2021-06-11 15:16:13 +02:00
Philipp Maier
eb984bd630 mgcp_client: drop nunnecessary else statement
There is an elarly return statement, so there is no need for an else
branch.

Change-Id: I96d0d468ccab302f9add206164f4d5b1b768bb48
2021-06-11 12:22:51 +02:00
Philipp Maier
b3d14eb552 mgcp_network: refactor MGCP_DUMMY_LOAD
The constant MGCP_DUMMY_LOAD is used ambigously. Sometimes it is used as
initalizer for an array, sometimes it is used as a single byte. Also the
name is not very expressive. Lets refactor this.

Change-Id: I21d96cefeeb647958bfa1e22a0ea030884746fad
Related: OS#4005
2021-06-07 20:14:35 +00:00
Pau Espin Pedrol
907744e2fc Use new stat item/ctr getter APIs
Generated with spatch with this and similat snippets:
"""
@@
expression E1, E2;
@@
- &E2->ctr[E1]
+ rate_c

Change-Id: I53b75ea8a88bc1ae4ceb479ed272865054de9665
2021-06-04 17:57:34 +02:00
Philipp Maier
776846a0b9 mgcp_common, mgcp_udp_send: make parameter buf const
When mgcp_udp_send() is called, the memory where *buf is pointing to is
never modified. It should be marked as const.

Change-Id: Iac90de5beb19bf52586ac6ffeab9eb5152edf339
2021-05-20 14:22:08 +02:00
Neels Hofmeyr
59e7cf4437 add osmo_mgcpc_ep_ci_get_remote_rtp_info()
So far an mgcp_client user can get the RTP address+port information that
the MGW has returned upon a CRCX. Add this function to return the other
RTP end, i.e. address+port that the MGW was told to send RTP to.

This will be used to fix the MGCP in osmo-bsc, which so far mixes up the
two RTP ends and compares the MSC's RTP address+port with the MGW's one
and hence fails to skip unnecessary MDCX.

Change-Id: Ibb488925827d9dc0ccb1f8d6d84728745d086793
2021-05-19 19:05:44 +02:00
Keith
b2064423fe Log some useful messages at ERROR/INFO instead of DEBUG
Change-Id: I22cbecab8d9f7a1980387f16c9a8da444aaa0311
2021-05-10 17:45:49 -05:00
Philipp Maier
97a9312be8 mgcp_network: fix implicit address loopback
A call agent may send a CRCX to create a connection in LOOPBACK mode but
without specifiying the destination address. In those cases the MGW
should deduct the destination address from the first incoming RTP
packet.

Unfortunately this is currently blocked by an OSMO_ASSERT that checks the
current sa_familiy against the sa_family from the incoming packet. This
makes no sense since the current sa_family is still uninitalized, which
is expected and not an error since the code that follows will initalize
it.

It also makes sense not to access the osmo_sockaddr struct members
individually but rather copy the address as a wohle.

Since the event only happens once and since it is also somewhat special
it makes sense to log the event as well.

Change-Id: I2dbd6f62170a7f62e5287d04a4ee6716b8786c26
Related: OS#5123
2021-05-10 12:50:34 +00:00
Neels Hofmeyr
427cede4ba tweak termination DLCX log msg
Sending a DLCX upon FSM cleanup is not unusual. Move the log about that
DLCX to INFO, and also print the endpoint and conn identifier.

Change-Id: Id723d949f101b66fb75296d01489d9dac350c7c8
2021-05-08 09:05:01 +00:00
Neels Hofmeyr
7371663aeb send DLCX only once
If the mgcp_client_fsm gets terminated in ST_DLCX_RESP, it has already
sent a DLCX to the MGW. So do not send a second one.

I noticed the duplicate DLCX for the same endpoint conn identifier while
running TTCN3 tests and watching the network trace of test teardown.

Change-Id: I35e415f67946b73c74408afe265618cfe4f72b0b
2021-05-08 09:05:01 +00:00
Keith
fe53edd776 Add vty command 'show mgcp active'
With just one E1 line, the 'show mgcp' command outputs
several hundred lines to the vty. Add a 'active' parameter to
only show endpoints that are active.

Change-Id: I23a26b4fdc03d8b2469d293dd6c06ed83ce739e9
2021-05-07 19:00:17 +00:00
Harald Welte
4f6a7ad5f8 manual: Include QoS chapter and add osmo-mgw specific example
Change-Id: I46f632f52a86a50242689a0132a7a7cb2a8feb12
Depends: osmo-gsm-manuals.git Id344c29eda2a9b3e36376302b425e9db1f6c0f28
2021-04-29 21:26:15 +02:00
Harald Welte
55a9229922 mgw: Add support for setting socket priority from VTY
This is useful for affecting the 802.1Q PCP value without any separate
external packet filter rules for classification.

Change-Id: I69136c6dd114c24b1dace034e75dba5157bac37e
Depends: libosmocore.git I89abffcd125e6d073338a5c6437b9433220e1823
2021-04-29 21:25:33 +02:00
Harald Welte
7802ccc8d6 switch from osmo_sock_set_dscp() to OSMO_SOCK_F_DSCP()
libosmocore If22988735fe05e51226c6b091a5348dcf1208cdf introduces
an even more convenient mechanism for specifying the DSCP of
an IP socket via OSMO_SOCK_F_DSCP()

Change-Id: If0b11dea08716ed3952a25b546b2a9bd013857bf
2021-04-28 20:27:37 +02:00
Harald Welte
3ff5151661 manual: don't define fig-bsc twice
Change-Id: Ibaed44a8de5425b420820a13f14c92c38b9c5fd9
2021-04-28 20:27:37 +02:00
Harald Welte
5936a9c23e TOS bits != DSCP
We have VTY options that allow to set the DSCP value.  However, we
then call a function to set the TOS bits in the kernel.  This is
very wrong.  The DSCP is only the upper 6 bits of the 8-bit TOS
value, and hence we are mussing that translation.

As libosmocore now has a helper function osmo_sock_set_dscp(),
let's make use of it and don't care about the low-level details.

However, this means we need to finally remove the deprecated
alias for "rtp ip-tos <0-255>".

Closes: OS#5137
Change-Id: I9c18c90273be97aedd2ad212b82f650e35c32851
Depends: libosmocore.git Ia4ba389a5b7e3e9d5f17a742a900d6fd68c08e40
2021-04-28 20:27:11 +02:00
Harald Welte
9ffaba7c1b Bump version: 1.8.0.1-535e → 1.8.1
Change-Id: Ib92e6ca89e1406d3707a94063975fe338cf67a9e
2021-02-24 10:56:17 +01:00
Harald Welte
535ede2598 attempt to fix RPM spec file after recent soversion bump
In I64ff22193ab2a95a9a7d66e9957a875d096e23de the soversion was
chhanged, but the spec.in file was not adjusted accordingly.

Change-Id: I45d7321adb2db8e7b9ea41b6bcf0c6cc59984a0e
2021-02-24 10:54:32 +01:00
Pau Espin Pedrol
6ccdaa243f Bump version: 1.7.0.138-ace0b-dirty → 1.8.0
Change-Id: I64ff22193ab2a95a9a7d66e9957a875d096e23de
2021-02-23 18:28:45 +01:00
Pau Espin Pedrol
ace0b946ff tests: Replace deprecated API log_set_print_filename
Change-Id: I761d2bf99aa5a009ff489584d804634e58588125
2021-02-19 13:33:52 +01:00
Pau Espin Pedrol
a34036c296 .gitignore: Ignore new autofoo tmp files
Change-Id: I792f5cd80bee6572ee60269ac44a12d10b5e3a5f
2021-02-04 12:50:27 +01:00
Oliver Smith
9fec391d6e configure.ac: set -std=gnu11
Change-Id: Ic2a1f20be65810a86cdc36aaa459819146a0bfcc
2021-01-28 09:28:08 +00:00
Oliver Smith
a835fa85d7 contrib/jenkins: don't build osmo-gsm-manuals
Related: OS#4912
Change-Id: Idb179c5618797bb245fad857fa79242c43d539a2
2021-01-13 13:14:39 +01:00
Vadim Yanitskiy
2c66c15227 fixup mgcp_trunk: increase default number of virtual endpoints
In change I55605ea083565b6950d0820e3f72c50c9dc19ffa, the default
number of endpoints was increased to 512, however the
configuration examples were not updated.

Change-Id: I449a612065a5208c9f70ae74f594e8d45eb344cf
Related: OS#4711, SYS#5262
2021-01-02 11:29:29 +01:00
Philipp Maier
92a73cd637 mgcp_client: get rid of magic numbers for E1 slots
use NUM_E1_TS-1 instead of 31 in relation of E1 timeslot count

Change-Id: Iee134d70f05883fcd2e58e0b9c78ed70aea16695
2020-12-10 15:23:17 +00:00
Philipp Maier
6e2795bfbf usermanual: add chapter about mgcp endpoints
The manual does not say much about the endpoint naming, even though
osmo-mgw is oriented at RFC 3435 the endpoint names are specific to
osmo-mgw. In particular the E1/T1 endpoints and their overlapping need
some explaination

Change-Id: I16265eb667221959a69f33701d024bd8d9b22040
2020-12-01 12:04:38 +00:00
Philipp Maier
276b595361 configuration: add section about E1 trunks
The cunfiguration chapter does not say anything about E1 trunk
configurations, lets add a subsection that explains how an E1
trunk is added.

Change-Id: I4059771df0f115242398d1af499c837005a7dabc
2020-12-01 12:04:38 +00:00
Philipp Maier
3c293b418b mgcp_trunk: get rid of magic numbers for E1 slots
use NUM_E1_TS-1 instead of 31 in relation of E1 timeslot count

Change-Id: I1cf5fa17f7455448a08ec3c32febca450eadb21e
2020-11-27 15:12:33 +01:00
Philipp Maier
41425e9b85 mgcp_vty: add missing VTY commands for E1 trunks
The E1 trunk lacks the VTY commands force-realloc and rtp-accept-all.
However, the function that write the E1 trunk config includes those
commands. Also they would be applicable, so lets add those two commands
also for E1 trunks.

Change-Id: Ief2bc7502bb8d1e0f9c784d42edbe1aed5ffb728
2020-11-26 21:52:00 +01:00
Philipp Maier
31682a3274 mgcp_vty: fix config write for trunk 0
When a trunk 0 is created (which is legal) than it is impossible to
write this trunk back to the config. The reason for this that there is
still a filtering in place from the time where trunk 0 was not allowed.
This filter needs to be extended to filter only virtual trunk 0 but not
E1 trunk 0 out.

Change-Id: Iad6b577b5a711c35f98c477351fde567d8c87298
2020-11-26 00:41:36 +01:00
Philipp Maier
870f94b493 configuration: add note that changes to trunks need a restart
Change-Id: I06e3f8fed9a6784be773fbdd6a1e3d6b41f7b0bb
2020-11-25 18:13:25 +01:00
Philipp Maier
242e9ada91 configuration: drop note about lackin E1 support
We have now support for E1 trunks

Change-Id: If62f2b646c3b649fa3cbb5ea7007e17b80086bce
2020-11-25 16:22:40 +01:00
Philipp Maier
9b444fd417 configuration: remove hint towards trunk 0 limit
The trunk 0 was reserved for rtpbridge in earlier versions of osmo-mgw,
this was due to internal technical limitations which no longer exist.

Change-Id: Ic322f7dcf28db827187a4537e2634a887bd7b13b
2020-11-25 16:09:16 +01:00
Philipp Maier
e9473f610e overview: add graph to show E1 integration
Add a graph similar to "OsmoMGW used with OsmoMSC" that shows the
integration of a legacy E1 BTS into a AoIP network

Change-Id: I71dc2f4a188fbc25e81050be3dd4c83e1797e63d
2020-11-25 15:56:55 +01:00
Philipp Maier
53002b3a00 overview: fix graph "OsmoMGW used with OsmoMSC"
The graph "OsmoMGW used with OsmoMSC" shows a BSC entity that accepts
AoIP and RTP, however osmo-bsc has no RTP proxy functionality. It makes
probably more sense to remove the BTS from the graph and call "BSC" "2G
BSS"

Change-Id: I6c7d26b6e45d0f953b82bca3ae7b2f26600982b2
2020-11-25 15:47:35 +01:00
Philipp Maier
a098b65252 overview: fix graph "OsmoMGW used with OsmoBSC"
The graph "OsmoMGW used with OsmoBSC" shows an RTP and 3GPP AoIP going
to OsmoMSC, this is technically wrong since osmoMSC has no RTP proxy
functionality whatsoever. Since the graph is not so much about OsmoMSC
it makes more sense to label OsmoMSC with "core-network", then it makes
sense and correctly highlights the role of osmo-mgw on the BSS side.

Change-Id: If3550a101e1e3cc2a25e21dcfe5474134015a6a7
2020-11-25 15:38:49 +01:00
Philipp Maier
78b0055e5e overview: update section limitations.
The limitations section is outdated. We now have support for osmux and
E1 timeslots with trau frames. However, we did not mention that we still
have no transcoding as well.

Change-Id: Ia0fe8be96bbf880cfcd9d18256f4ac23a6efae79
2020-11-25 15:11:30 +01:00
Vadim Yanitskiy
648bec3982 main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
Change-Id: Icb19a635fb7526058d3c47e24ed7d72584dffb0f
Depends: Ie2022a7f9e167e5ceacf15350c037dd43768ff40
Related: SYS#4910
2020-10-24 05:21:06 +07:00
Harald Welte
c2a8f59560 use osmo_fd_setup() whenever applicable
Change-Id: I1586e855d37670af2602fc26b5d1fc72a32d1929
2020-10-21 11:56:17 +00:00
Pau Espin Pedrol
38404969df contrib/jenkins: Enable parallel make in make distcheck
Change-Id: I8b73a9cdd0e481075a234abd9e94bd5c4396f168
Related: OS#4421
2020-10-12 19:34:58 +02:00
Philipp Maier
19c430feba mgcp_vty: add user attributes to configuration commands
To make clear which configuration changes (configure terminal)
apply when, add appropriate user attributes to VTY commands.

Change-Id: I2d9487801b3b78f94577264b56d217c926ef76a9
Related: SYS#4937, OS#1601
2020-10-08 19:26:51 +02:00
Vadim Yanitskiy
3ba409558e vty: use install_lib_element() and install_lib_element_ve()
See https://lists.osmocom.org/pipermail/openbsc/2020-October/013278.html.

Change-Id: I0eff9e0daa1c4327fec8034755986d768f9ba511
Depends: I8baf31ace93c536421893c2aa4e3d9d298dcbcc6
Related: SYS#4937
2020-10-04 16:48:55 +07:00
Philipp Maier
60be627557 mgcp_e1: do not expose function mgcp_e1_init()
The initialization of the E1 line in mgcp_e1.c is controlled internally,
there is no need to expose the function mgcp_e1_init(), lets make it
static and remove the prefix mgcp_

Change-Id: I6aba1c55c9b1d729709ee1fba2994c77bd848a9b
2020-09-23 10:25:52 +02:00
Philipp Maier
8cfe7df3f1 mgcp_vty: deprecate bind early command
The VTY command "bind early" is deprecated but it prints an error
message and the DEFUN is not set to DEFUN_DEPRECATED.

Change-Id: I594a87d2f63826a9d7b4f6a380586b08b3b79518
2020-09-23 10:25:52 +02:00
Philipp Maier
ba94b6d7be mgcp_vty: remove remains of loopback functionality
There exist trunk_loop commands, which sets an trunk->audio_loop
variable, however all it does is to turn on a log message. There is no
actual implementation present. Lets set the VTY commands to
DEFUN_DEPRECATED and remove the variable.

Change-Id: I72b0f8b908e32643e6e3db6ac024371b13c074a1
2020-09-22 16:17:38 +02:00
Pau Espin Pedrol
30e01355f6 cosmetic: Fix typo in comment
Change-Id: Ie982e6721f9840ac9c0bca62646f5c97cc0b1139
2020-09-21 15:45:38 +02:00
Pau Espin Pedrol
06624e13d4 mgw: Fix return value documentation for API mgcp_verify_call_id
Change-Id: Ib5d32baf3a10dad73de29b4388eab14b93ab6f09
2020-09-21 15:45:38 +02:00
Pau Espin Pedrol
19539866e5 mgw: Avoid logging notice message each time we receive nt param in LCO
We don't really use it so far and it doesn't deserve a NOTICE message.

Change-Id: I058dc37fe6229e879284a8f5e7677d6016129c47
2020-09-21 15:45:21 +02:00
Pau Espin Pedrol
1dc2dcebbf cosmetic: Fix typo in comment
Change-Id: I87894dc710823226c1891c919a11ea32c326d3b9
2020-09-21 11:25:18 +02:00
Pau Espin Pedrol
6049a63d1d mgw: Don't be case-sensitive when parsing X-Osmo-IGN param
Some implementations like our TTCN3 encoder set all param characters in
caps.

Related: SYS#5063
Change-Id: Ie4bc5e86551c55021ca6ca2fbc6fc56a26f5fb16
2020-09-21 11:03:25 +02:00
Philipp Maier
3ef8e76534 cosmetic: mgcp_client_fsm: change error message.
The error message: "abrupt FSM termination with connections still
present, sending unconditional DLCX..." implies a more serious problem
than in actually is. Even when connections are present on the
mgcp_client_fsm while it terminates, normal operation is still possible.
Lets change the loglevel to NOTICE and remove the "aprupt" from the
phrase.

Change-Id: I9749c024e208835bd4188bace13f723008de54c8
Related: SYS#5082
2020-09-18 08:46:21 +00:00
Neels Hofmeyr
fbf07f3f69 change timer T2427001 to X2427
libosmo-mgcp-client looks up this timer in a caller provided osmo_tdef
definition. So far, all of our libosmo-mgcp-client callers do not configure
such a timer, so that we always use the default timer value.

We have introduced X timers (negative numbers) to indicate Osmocom specific
timers, and reserve T timers for 3GPP specified ones. So now is still a good
chance to move this timer to the Osmocom X realm.

Remove a comment about this timer at an unrelated place. It is still described
at osmo_mgcpc_ep_alloc().

Change-Id: If097f52701fd81f29bcca1d252f4fb4fca8a04f7
2020-09-16 00:02:31 +02:00
Pau Espin Pedrol
de133113a0 mgw: osmux: Fix conn watchdog timeout not updated
It is currently done upon receival of RTP packets in rx_rtp for pure RTP
conns, but nothing similar is done for Osmux conns, which eventually
trigger a connection time out.

Change-Id: Id592d7db7b9399a497176e0d28cc826b3bce48c0
2020-09-08 17:51:45 +02:00
Pau Espin Pedrol
6d0a59a1bf mgw: Release endpoint after last conn times out
Otherwise some state is kept, like the previous CallId, which may then
provoke issues next time the endpoint is to be used.

Change-Id: I3ac4f4542c1c8c877127c64acce6c82b458f697f
2020-09-08 16:50:24 +02:00
Pau Espin Pedrol
2491401932 mgw: osmux: Avoid sending packets on recvonly connection
Change-Id: I87b1fb7d73cbbb2a5d4d8a40a9527a3e05d9947b
2020-09-08 12:57:35 +02:00
Pau Espin Pedrol
fbbe8f2f98 mgw: Announce and rebind new local address if change required during MDCX
MDCX may provide 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.

Change-Id: Iaed424e2c209e1753e1f579752fc684aaad7a512
2020-09-07 18:12:59 +02:00
Pau Espin Pedrol
71d42e778a mgw: Find and store RTP conn local_addr once during CRCX handling
It doesn't make sense to call the function several times since anyway we
are only binding during
allocate_port()->mgcp_bind_net_rtp_port()->bind_rtp()->mgcp_create_bind()->osmo_sock_init2().

Let's better calculate the local IP addr once and use that stored value.
THis is a previous step towards next commit updating the local IP addr
and re-bindng if encessary.

Change-Id: I803b99c5e5fe0f92a5bf6796d8c25df88d1608e6
2020-09-07 18:12:59 +02:00
Pau Espin Pedrol
8a2a1b22fe mgw: Introduce VTY cmd 'rtp bind-ip-v6' command
This commit allows for fully IPv6 systems to work fine. However, if a
remote endpoint still wants to use IPv4, it will fail since at this
point osmo-mgw still doesn't re-bind the local end of the connection to
an IPv4 after having initially bound it to an IPv6 one. This kind of
scenarios get fixed in next commits.

TODO: really bind the socket if a different IP address is requested.

Change-Id: I8ed94bd3f674f498e6ba315f44a351fff9c1be15
2020-09-07 18:12:59 +02:00
Pau Espin Pedrol
a790f0c082 mgw: Initial IPv6 support
This commit contains the bulky work of moving all address parsing to
support IPv6 together with IPv4.
Some specific patches required for full IPv6+IPv4 support requiring
behavioral changes come after this one.

Full Osmux IPv6 support is left out of the scope of this patch.

Depends: libosmocore.git Ie07a38b05b7888885dba4ae795e9f3d9a561543d (> 1.4.0)
Depends: libosmocore.git I59bf4b4b3ed14766a5a5285923d1ffa9fc8b2294 (> 1.4.0)
Change-Id: I504ca776d88fd852bbaef07060c125980db3fdd7
2020-09-07 18:12:59 +02:00
Pau Espin Pedrol
0ab152b2c6 mgw: Fix mgcp_rtp_end field description comment
Change-Id: Ieb044daaaa47572cd9a2524ea69e903200527d17
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
2741d6bb0e mgcp_client: copy back Connection Information from MDCX ACK
This is needed in case MGW changes the local IP address (for instance
because it initlaly offered an IPv4 address, and a client submitted a
remote IPv6 address, so MGW needs then to offer a local IPv6 address for
the RTP connection to be possible).

Change-Id: Ie964412b81fe6e10914790baaea724ca5f772adc
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
74d0e5c318 mgcp_client: Deprecate unused IPv4-only API
The API and related implementation fields are not used internally nor
externally, and only support IPv4. Let's simply deprecate the API and
drop all the uneeded implementation.

Change-Id: I905d4c4efabb6b4a4bc5c02e956808777243cadc
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
c4ef4a21c6 mgcp_client: Support validating IPv6 addresses in CRCX and MDCX commands
Change-Id: Ie97675f173dc3a223f6c2ced913906d760ffb732
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
ee2f33bf9a mgcp_client: Make MGCP_CLIENT_LOCAL_ADDR_DEFAULT IPv6 compatible
If "0.0.0.0", the default, is passed together with an IPv6 configured
address (ex: "mgw remote-ip ::1") in VTY, socket creation will fail due
to address version mismatch (because getaddrinfo() returns only an IPv4
address in the local result set).
If instead NULL is passed, then 2 entries are returned, one in IPv4 and
one in IPv6, and osmo_sock_init2 is smart enough to take one or another
when passed AF_UNSPEC.

Change-Id: I1be6f3b71486ce1782ba6b8c62f25145b42ec894
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
531470a0ca mgcp_client: Allow setting IPv6 addresses
Change-Id: I257218b2ad7cbdd0ac4ae7fa75802bed74ce983f
2020-09-07 15:55:30 +02:00
Pau Espin Pedrol
9dc73593a3 mgcp_client: Allow submitting and parsing IPv6 addr in SDP
Existing mgcp_client_test code required the '.' to trigger the same code
path, since with this commit we do extra checks and without a dot the
address is not accepted as IPv4 by osmo_ip_str_type().

Change-Id: I936bf57d37f5f0607dfe7fc66c37e424c3793f9b
2020-09-07 15:55:30 +02:00
Philipp Maier
ae6858bddf mgcp_trunk: increase default number of virtual endpoints
The VTY default for the number of endpoints is 32. This is sufficient
for small setups and lab testing, but for medium sized setupts the limit
might be reached soon. Lets increase the default to 512 virtual endpoints.

Change-Id: I55605ea083565b6950d0820e3f72c50c9dc19ffa
Related: OS#4711
2020-09-07 12:11:25 +02:00
Philipp Maier
99d4d368e8 mgcp_endp: use NUM_E1_TS from e1_input.h
do not introduce another define constant, use NUM_E1_TS as number of E1
timeslots.

Change-Id: I3bbfb6822d5595f9d243849141883490fa8037cb
2020-09-07 12:00:51 +02:00
Pau Espin Pedrol
8667d5169d mgcp_client: Use INET6_ADDRSTRLEN to store addresses in str format
Warning: This breaks libosmo-mgcp-cli ABI!

Related: SYS#4915
Change-Id: Ib778e9a72764103b52a462ea3c7fb56b23c1bcd6
2020-08-31 17:10:08 +02:00
Pau Espin Pedrol
1add5a53cb mgcp-client: Fix trailing whitespace in mgcp_client_fsm.h
Change-Id: Iad9ee764c1b6d7960a810a3eef95b207596e4796
2020-08-31 17:10:08 +02:00
Pau Espin Pedrol
729bf3e45a mgcp-client: Support IPv6 in osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr() implementation
Change-Id: Ibbfc1c2485636502dc0f3aef3922432cc7fd6170
2020-08-31 17:10:08 +02:00
Philipp Maier
2f34b53b5b mgcp_e1: remove unused struct member trunk->e1.line
The struct member trunk->e1.line is never set. Also it is always
possible to use e1inp_line_find() to get a pointer to the e1.line.
Lets remove it.

Change-Id: Id4ff52285917ce3885b8dad3a16270999c9da0aa
2020-08-31 16:21:03 +02:00
Philipp Maier
ad79f9eb99 mgcp_e1: make E1 ts initalization more debugable
The E1 timeslot initalization may fail silently in the last steps. There
is an error code returned, but no log lines are printed. This can make
debugging difficult.

Change-Id: I9aab17fc1ba6666c81b14035a8f1f17e5a55adaf
2020-08-31 16:21:03 +02:00
Harald Welte
9e494e67c7 Add example osmo-mgw configuration file for Abis/E1
In this example, we are using the first span (0) of the first DAHDI card
and use it as 'trunk 1' in the MGW.

Change-Id: I0a97da5163a94379b327403b1258696855836bad
2020-08-28 15:00:32 +02:00
Alexander Couzens
5322473d04 configure.ac: require libosmoabis + libosmotrau >= 1.0.0
Since osmo-mgw supports trau frames it requries a newer version.
The spec file already requires those newer version.

Change-Id: If6c7ecdde09c6e09ded7e0959b7765a01a31d702
2020-08-21 18:37:42 +02:00
Pau Espin Pedrol
c57ad7ff9a cosmetic: Rename main talloc ctx
It contained name from a different program, probably due to main.c being
copied over during project start.

Change-Id: I4bfa40eec0277705f5d3335d779bff35518470a8
2020-08-20 08:43:52 +00:00
Pau Espin Pedrol
c59b5c533d Support setting rt-prio and cpu-affinity mask through VTY
Change-Id: Icfafea073a0cdac289a651d61632b4c6af39c6a9
Depends: libosmocore.git Change-Id If76a4bd2cc7b3c7adf5d84790a944d78be70e10a
Depends: osmo-gsm-masnuals.git Change-Id Icd75769ef630c3fa985fc5e2154d5521689cdd3c
Related: SYS#4986
2020-08-20 08:43:52 +00:00
Philipp Maier
0653cc8a7c mgcp_trunk: drop "trunk 0" limitation
Due to the internal handling of the trunks it was not possible to allow
an E1 trunk that has the ID 0. However this limitation is no longer
present, so we now can allow an E1 trunk with ID 0.

Change-Id: I302c2007628f607033686e277c407232351e66ad
Related: OS#2659
2020-08-20 06:21:41 +00:00
Philipp Maier
246233d0d4 cosmetic: add missing new-line
Change-Id: I4a4a7515e8d92ab39576c33765dd3dc581453ceb
2020-08-18 20:11:38 +02:00
Philipp Maier
a910a81b7c mgcp_protocol: log when endpoint is unavailable
When endpoints become unavailable when MDCX/CRCX/DLCX are executed on
them a major problem may be the cause, lets make sure that those events
are logged.

Change-Id: I059b7e29f960e75a53bfb5dfb2b83ab3d79e84f3
2020-08-18 20:11:11 +02:00
Philipp Maier
c8acee2234 mgcp_e1: use return value of e1inp_line_update()
The function e1inp_line_update() is called without assigning its return
code to the rc variable.

Change-Id: Ia72ea2dca210b038766151d547f66b7b7139a2c4
Fixes: CID#212160
2020-08-15 07:43:38 +00:00
Harald Welte
55863e42c1 osmo-mgw.spec.in: Add missing dependency to libosmotrau
Change-Id: I2d5f8b1d852079b8f82adb681d7e6b72a8358cf1
2020-08-14 09:48:35 +02:00
Vadim Yanitskiy
6177cae2a2 debian/control: change maintainer to the Osmocom team / mailing list
Change-Id: I1bb002b257d4bef83d181d615411e443c1831f00
2020-08-13 16:09:02 +07:00
Harald Welte
6af3ccf65d osmo-mgw.spec.in: Fix dependency to libosmoabis
Confusingly, in Debian the package is called libosmo-abis, but in
the CentOS/RPM it's called libosmoabis.  Fixes a bug introduced
in I45717bda3ef7eba1ef59b993cc8a69bf2f92a29f

Change-Id: I97dfec72a99295148e84e60c1e5037381f736c03
2020-08-13 09:35:12 +02:00
Harald Welte
03cb5f3397 debian/control + SPEC: Add missing build dependency to libosmo-abis
In I6b93809b5ac7d01af55888347dd787b0bc997ae1 we introduced E1 support
to osmo-mgw, but failed to add it to the build dependencies of the
Debian packages, making network:osmocmo:nightly builds fail.

Change-Id: I45717bda3ef7eba1ef59b993cc8a69bf2f92a29f
2020-08-13 07:28:55 +02:00
60 changed files with 4673 additions and 1776 deletions

563
.clang-format Normal file
View File

@@ -0,0 +1,563 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 4.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0
BeforeCatch: false
BeforeElse: false
IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0
#SplitEmptyRecord: true # Unknown to clang-format-4.0
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- '__ata_qc_for_each'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- '__bio_for_each_bvec'
- 'bio_for_each_bvec'
- 'bio_for_each_bvec_all'
- 'bio_for_each_integrity_vec'
- '__bio_for_each_segment'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bitmap_for_each_clear_region'
- 'bitmap_for_each_set_region'
- 'blkg_for_each_descendant_post'
- 'blkg_for_each_descendant_pre'
- 'blk_queue_for_each_rl'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf_for_each_spilled_reg'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'device_for_each_child_node'
- 'displayid_iter_for_each'
- 'dma_fence_chain_for_each'
- 'do_for_each_ftrace_op'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_crtc_reverse'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'flow_action_for_each'
- 'for_each_acpi_dev_match'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_aggr_pgid'
- 'for_each_available_child_of_node'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_dapms'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_card_widgets'
- 'for_each_card_widgets_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_cmsghdr'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_comp_order'
- 'for_each_console'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
- 'for_each_cpu_wrap'
- 'for_each_dapm_widgets'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_dtpm_table'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_link_codecs'
- 'for_each_link_cpus'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_member'
- 'for_each_memcg_cache_index'
- 'for_each_mem_pfn_range'
- '__for_each_mem_range'
- 'for_each_mem_range'
- '__for_each_mem_range_rev'
- 'for_each_mem_range_rev'
- 'for_each_mem_region'
- 'for_each_migratetype_order'
- 'for_each_msi_entry'
- 'for_each_msi_entry_safe'
- 'for_each_msi_vector'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_net_rcu'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_private_obj_in_state'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_nonreserved_multicast_dest_pgid'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pci_msi_entry'
- 'for_each_pcm_streams'
- 'for_each_physmem_range'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_prop_codec_conf'
- 'for_each_prop_dai_codec'
- 'for_each_prop_dai_cpu'
- 'for_each_prop_dlc_codecs'
- 'for_each_prop_dlc_cpus'
- 'for_each_prop_dlc_platforms'
- 'for_each_property_of_node'
- 'for_each_registered_fb'
- 'for_each_requested_gpio'
- 'for_each_requested_gpio_in_range'
- 'for_each_reserved_mem_range'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dais'
- 'for_each_rtd_components'
- 'for_each_rtd_cpu_dais'
- 'for_each_rtd_dais'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sgtable_dma_page'
- 'for_each_sgtable_dma_sg'
- 'for_each_sgtable_page'
- 'for_each_sgtable_sg'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- '__for_each_thread'
- 'for_each_thread'
- 'for_each_unicast_dest_pgid'
- 'for_each_vsi'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hctx_for_each_ctx'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- 'hlist_for_each_entry_srcu'
- '__hlist_for_each_rcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'ide_host_for_each_port'
- 'ide_port_for_each_dev'
- 'ide_port_for_each_present_dev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'inet_lhash2_for_each_icsk_rcu'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kunit_suite_for_each_test_case'
- 'kvm_for_each_memslot'
- 'kvm_for_each_vcpu'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_entry_srcu'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'pcl_for_each_chunk'
- 'pcl_for_each_segment'
- 'pcm_for_each_format'
- 'ping_portaddr_for_each_entry'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rb_for_each'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'rdma_umem_for_each_dma_block'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- '__rq_for_each_bio'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'shdma_for_each_chan'
- '__shost_for_each_device'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'tb_property_for_each'
- 'tcf_exts_for_each_action'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'while_for_each_ftrace_op'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'zorro_for_each_dev'
- 'for_each_line'
- 'for_each_non_empty_line'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

6
.gitignore vendored
View File

@@ -16,6 +16,7 @@ src/osmo-mgw/osmo-mgw
*.gcda
*.gcno
*.pc
*~
#configure
aclocal.m4
@@ -63,3 +64,8 @@ doc/manuals/common
doc/manuals/build
contrib/osmo-mgw.spec
#vs code
.cache
.vscode

View File

@@ -9,6 +9,8 @@ AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_TESTDIR(tests)
CFLAGS="$CFLAGS -std=gnu11"
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -34,11 +36,6 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
dnl check for AX_CHECK_COMPILE_FLAG
m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
])
dnl checks for libraries
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
@@ -47,13 +44,16 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DLSYM)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.2.0)
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.2.0)
CFLAGS="$CFLAGS -pthread"
LDFLAGS="$LDFLAGS -pthread"
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
@@ -85,15 +85,6 @@ then
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
fi
dnl Checks for typedefs, structures and compiler characteristics
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,

View File

@@ -36,7 +36,6 @@ osmo-build-dep.sh libosmo-netif
# Additional configure options and depends
CONFIG=""
if [ "$WITH_MANUALS" = "1" ]; then
osmo-build-dep.sh osmo-gsm-manuals
CONFIG="--enable-manuals"
fi
@@ -50,18 +49,18 @@ set -x
cd "$base"
autoreconf --install --force
./configure --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
./configure --enable-sanitize --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
$MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
LD_LIBRARY_PATH="$inst/lib" \
DISTCHECK_CONFIGURE_FLAGS="--enable-vty-tests --enable-external-tests $CONFIG" \
$MAKE distcheck \
$MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE maintainer-clean
$MAKE $PARALLEL_MAKE maintainer-clean
osmo-clean-workspace.sh

View File

@@ -29,28 +29,30 @@ BuildRequires: pkgconfig >= 0.20
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libosmo-netif) >= 0.6.0
BuildRequires: pkgconfig(libosmocore) >= 1.0.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.1.0
BuildRequires: pkgconfig(libosmogsm) >= 1.0.0
BuildRequires: pkgconfig(libosmovty) >= 1.0.0
BuildRequires: pkgconfig(libosmocoding) >= 1.0.0
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
BuildRequires: pkgconfig(libosmocore) >= 1.6.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.6.0
BuildRequires: pkgconfig(libosmogsm) >= 1.6.0
BuildRequires: pkgconfig(libosmovty) >= 1.6.0
BuildRequires: pkgconfig(libosmocoding) >= 1.6.0
BuildRequires: pkgconfig(libosmoabis) >= 1.2.0
BuildRequires: pkgconfig(libosmotrau) >= 1.2.0
%{?systemd_requires}
%description
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
%package -n libosmo-mgcp-client6
%package -n libosmo-mgcp-client9
Summary: Osmocom's Media Gateway Control Protocol client library
Group: System/Libraries
%description -n libosmo-mgcp-client6
%description -n libosmo-mgcp-client9
Osmocom's Media Gateway Control Protocol client library.
%package -n libosmo-mgcp-client-devel
Summary: Development files for Osmocom's Media Gateway Control Protocol client library
Group: Development/Libraries/C and C++
Requires: libosmo-mgcp-client6 = %{version}
Requires: libosmo-mgcp-client9 = %{version}
%description -n libosmo-mgcp-client-devel
Osmocom's Media Gateway Control Protocol client librarary.
@@ -88,8 +90,8 @@ find %{buildroot} -type f -name "*.la" -delete -print
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%post -n libosmo-mgcp-client6 -p /sbin/ldconfig
%postun -n libosmo-mgcp-client6 -p /sbin/ldconfig
%post -n libosmo-mgcp-client9 -p /sbin/ldconfig
%postun -n libosmo-mgcp-client9 -p /sbin/ldconfig
%if 0%{?suse_version}
%preun
@@ -111,13 +113,14 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-mgw
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
%{_bindir}/osmo-mgw
%{_unitdir}/osmo-mgw.service
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
%files -n libosmo-mgcp-client6
%{_libdir}/libosmo-mgcp-client.so.6*
%files -n libosmo-mgcp-client9
%{_libdir}/libosmo-mgcp-client.so.9*
%files -n libosmo-mgcp-client-devel
%{_libdir}/libosmo-mgcp-client.so

View File

@@ -1,5 +1,7 @@
[Unit]
Description=Osmocom Media Gateway (MGW)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple

293
debian/changelog vendored
View File

@@ -1,3 +1,296 @@
osmo-mgw (1.9.2) unstable; urgency=medium
* systemd: depend on networking-online.target
-- Oliver Smith <osmith@sysmocom.de> Fri, 26 May 2023 14:57:36 +0200
osmo-mgw (1.9.1) unstable; urgency=medium
[ Vadim Yanitskiy ]
* libosmo-mgcp: e1: fix memleaks in e1_recv_cb()
-- Harald Welte <laforge@osmocom.org> Mon, 18 Apr 2022 10:58:50 +0200
osmo-mgw (1.9.0) unstable; urgency=medium
[ Harald Welte ]
* TOS bits != DSCP
* manual: don't define fig-bsc twice
* switch from osmo_sock_set_dscp() to OSMO_SOCK_F_DSCP()
* mgw: Add support for setting socket priority from VTY
* manual: Include QoS chapter and add osmo-mgw specific example
[ Keith ]
* Add vty command 'show mgcp active'
* Log some useful messages at ERROR/INFO instead of DEBUG
[ Neels Hofmeyr ]
* send DLCX only once
* tweak termination DLCX log msg
* add osmo_mgcpc_ep_ci_get_remote_rtp_info()
* check_rtp_destin(): clarify log msg
* mgcp_client_fsm delete: set mgcp_client as ctx, not NULL
* mgcp_client_endpoint_fsm: on term, still let conns wait for DLCX OK
* mgcp_client_fsm: add missing log_subsys
* mgcp_client: add logging on received MGCP messages
[ Philipp Maier ]
* mgcp_network: fix implicit address loopback
* mgcp_common, mgcp_udp_send: make parameter buf const
* mgcp_network: refactor MGCP_DUMMY_LOAD
* mgcp_client: drop nunnecessary else statement
* mgcp_client: fix error handling in mgcp message generation
* mgcp_protocol: fix loop that sends dummy RTP packets
* mgw_main: fix loop that resets all endpoints
* mgcp_trunk: drop ws line
* mgcp_ratectr: drop ws line
* mgcp_ratectr: fix sourcecode formatting
* mgcp_trunk: add value string for trunk type.
* mgcp_ratectr: refactor rate counter and set group name
* mgcp_protocol: forward declare mgcp_endpoint
* mgcp_endp: make wildcarded detection separate
* mgcp_protocol: refactor request handler array
* mgcp_trunk: use unsigned int instead of int as trunk_nr
* mgcp_protocol: refactor MGCP request handling
* mgcp_ratectr: add stats items to monitor trunk usage
* mgcp_msg: add trunk parameter to mgcp_check_param for logging
* mgcp_protocol: refactor function create_response_with_sdp
* mgcp_protocol: add support for wildcarded DLCX
* remove struct member wildcarded_req from struct mgcp_endpoint
* mgcp_lient: remove unsubstantial FIXME note
* mgcp_protocol: assert endp when it becomes mandatory
* mgcp_trunk: check MGW domain name earlier
* mgcp_ratectr: add stats items to monitor trunk usage
* mgcp_client: fix typo Initalize -> Initialize
* mgcp_protocol: get rid of policy_cb and change_cb
* mgcp_ratectr: do not set talloc destructor on library allocated item
* mgcp_client: allow to reset endpoints on startup
* mgcp_client_vty: remove unnecessary checks
* mgcp_client: do not print (null) when address is ANY
* mgcp_client: refactor function init_socket
* libosmo-mgcp-client: extend the mgcp_client for MGW pooling
* mgcp_client_vty: add missing docstrings
* mgcp_client_vty: add OSMO_ASSERT on pool parameter
* mgcp_client_vty: fix docstrings for mgw-pool
* mgcp_client_vty: cosmetic: doc string should terminated with \n
* mgcp_client_vty: fixing docstring
* mgcp_ratectr: remove unusued rate counters
* mgcp_client: fix typo in doxygen comment
* mgcp_client: add MGW name as logging context
[ Pau Espin Pedrol ]
* Use new stat item/ctr getter APIs
* constify arg in addr_is_any()
* Define patch_ssrc as bool type
* constify some function arg pointers
* mgcp_network.c: Reorder some functions in file
* mgcp_send_dummy: Check RTP destination is available before attempt tx
* mgw: rx CRCX: Avoid sending dummy rtp if remote address not provided
* Fail rx MDCX sendrecv with invalid remote addr
* Take into account Marker bit when patching RTP stream
* Use DLMGCP instead of DLGLOBAL in log lines
* Fix attribute parsing on gcc 11.1.0
[ neels ]
* Revert "mgcp_ratectr: add stats items to monitor trunk usage"
[ Daniel Willmann ]
* contrib/jenkins: Use ASAN for osmo-mgw
[ Oliver Smith ]
* mgcp_client_vty: add missing NO_STR
* Revert "Turn some compiler warnings into errors"
[ Eric ]
* add vscode stuff to gitignore
* configure.ac: fix maybe-uninitialized for clang
* fix missing includes and forward declarations
* rename do_retransmission
* mgcp_sdp: fix potential leak
* stats: make sanitizers happy
* libosmo-mgcp: cleanup audio codex alloc
* libosmo-mgcp: atomic rate counter group indexes
* libosmo-mgcp: do not use the default msgb talloc context
* globally lock the portrange when trying to grab a port to prep for multithreading
* embed strings into structs
* adjust talloc context
* endp: do not cache cfg pointer
* add modified .clang-format
* rename strip_epname and find_specific_endpoint and make them available
* fix mgcp_conn_free_all
* fix up some docstrings that lost their dot
[ Vadim Yanitskiy ]
* libosmo-mgcp: use OSMO_STRLCPY_ARRAY in mgcp_codec_add()
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 16:59:21 +0100
osmo-mgw (1.8.1) unstable; urgency=medium
* attempt to fix RPM spec file after recent soversion bump
-- Harald Welte <laforge@osmocom.org> Wed, 24 Feb 2021 10:56:17 +0100
osmo-mgw (1.8.0) unstable; urgency=medium
[ Harald Welte ]
* Fix number of endpoints of default trunk
* Add CTRL interface to osmo-mgw
* Update per-trunk global packet/byte counters in real-time
* remove accidential TODO-RELEASE entry
* mgcp_protocol: Avoid code duplication between virtual + other trunks
* osmo-mgw.spec.in: Use %config(noreplace) to retain current config file
* mgcp_client_init(): consider "talloc returns NULL" case
* mgcp_client_pending_add(): Consider "talloc returns NULL" case
* libosmo-mgcp-client: fix memleak in case if no response is received
* debian/control + SPEC: Add missing build dependency to libosmo-abis
* osmo-mgw.spec.in: Fix dependency to libosmoabis
* osmo-mgw.spec.in: Add missing dependency to libosmotrau
* Add example osmo-mgw configuration file for Abis/E1
* use osmo_fd_setup() whenever applicable
[ Neels Hofmeyr ]
* fix vty dump_trunk: start from zero, do not omit first CONN
* allow larger MGCP client wqueue: 10 -> 1024
* add osmo-mgw --vty-ref-xml: dump VTY ref XML to stdout
* manuals: generate vty reference xml at build time
* refactor: use msgb to receive, pass and send RTP packets
* change timer T2427001 to X2427
[ Philipp Maier ]
* doc: do not bind osmo-mgw to random ip-address
* cosmetic: remove excess newlines
* mgcp: remove unused callback pointer
* mgcp: find better locations for LOGPCONN and LOGPENDP
* vty: fix unreachable code (error msg on trunk alloc fail)
* mgcp_vty: fix indentation
* osmo-mgw: rename struct mgcp_trunk_config and symbol tcfg
* mgcp_vty: fix indentation in VTY config write
* osmo-mgw: refactor endpoint and trunk handling
* mgcp_trunk: remove audio_name and audio_payload
* ratectr: move rate counter definitions into mgcp_ratectr.h
* cosmetic: fix doxygen
* cosmetic: fix doxygen
* cosmetic: fix doxygen for mgcp_cleanup_rtp_bridge_cb()
* trunk: get rid of virt_trunk pointer
* cosmetic: remove excess space
* endp: move endpoint name generation into mgcp_endp.c
* endp: add name generator function for E1 endpoints
* mgcp_client: add docstring for mgcp_client_rtpbridge_wildcard()
* mgcp_trunk: fix docstring for mgcp_trunk_alloc()
* mgcp_osmux: remove unused define constants
* mgcp_trunk: move enum mgcp_trunk_type to mgcp_trunk.h
* mgcp_trunk: use enum type for trunk type variable
* trunk: parse E1 trunk number
* endp: add typeset for e1-endpoints
* mgcp_conn: move struct mgcp_conn mgcp_conn.h
* mgcp_internal: remove forward declaration struct mgcp_endpoint_type
* endp: add E1 endpoint interlocking
* endp: require domain name also for E1 endpoints
* mgcp_trunk: pick trunk by number and type
* mgcp_client: add function to generate e1-endpoint names
* mgcp_endp: use define constant to define max number of E1 subslots
* mgcp_endp.c: cosmetic: fix sourcecode formatting
* mgcp_trunk: remove double check
* mgcp_test: do not access endpoint array elements directly
* mgcp_vty: fix endpoint number configuration
* mgcp_test: remove trunk2 from unit-test
* mgcp_trunk: use talloc_zero_array instead of _talloc_zero_array
* mgcp_protocol: remove unused variable
* mgcp_e1: finish E1 support, add E1 support from libosmoabis
* get rid of mgcp_internal.h
* mgcp_ratectr: fix comments in header file
* mgcp_e1: use return value of e1inp_line_update()
* mgcp_protocol: log when endpoint is unavailable
* cosmetic: add missing new-line
* mgcp_trunk: drop "trunk 0" limitation
* mgcp_e1: make E1 ts initalization more debugable
* mgcp_e1: remove unused struct member trunk->e1.line
* mgcp_endp: use NUM_E1_TS from e1_input.h
* mgcp_trunk: increase default number of virtual endpoints
* cosmetic: mgcp_client_fsm: change error message.
* mgcp_vty: remove remains of loopback functionality
* mgcp_vty: deprecate bind early command
* mgcp_e1: do not expose function mgcp_e1_init()
* mgcp_vty: add user attributes to configuration commands
* overview: update section limitations.
* overview: fix graph "OsmoMGW used with OsmoBSC"
* overview: fix graph "OsmoMGW used with OsmoMSC"
* overview: add graph to show E1 integration
* configuration: remove hint towards trunk 0 limit
* configuration: drop note about lackin E1 support
* configuration: add note that changes to trunks need a restart
* mgcp_vty: fix config write for trunk 0
* mgcp_vty: add missing VTY commands for E1 trunks
* mgcp_trunk: get rid of magic numbers for E1 slots
* configuration: add section about E1 trunks
* usermanual: add chapter about mgcp endpoints
* mgcp_client: get rid of magic numbers for E1 slots
[ Eric ]
* tests: dlopen does not imply availability of dlsym..
* configure.ac: fix libtool issue with clang and sanitizer
[ Alexander Chemeris ]
* vty: Prepend VTY output of counters for better visual separation.
* counters: Implement more useful counters.
* mgcp_network: Fix a typo in the comment bahviour -> behaviour
* rtp_bridge: Demote a chatty ERROR log message to DEBUG level.
[ Pau Espin Pedrol ]
* Use OSMO_FD_* instead of deprecated BSC_FD_*
* Support setting rt-prio and cpu-affinity mask through VTY
* cosmetic: Rename main talloc ctx
* mgcp-client: Support IPv6 in osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr() implementation
* mgcp-client: Fix trailing whitespace in mgcp_client_fsm.h
* mgcp_client: Use INET6_ADDRSTRLEN to store addresses in str format
* mgcp_client: Allow submitting and parsing IPv6 addr in SDP
* mgcp_client: Allow setting IPv6 addresses
* mgcp_client: Make MGCP_CLIENT_LOCAL_ADDR_DEFAULT IPv6 compatible
* mgcp_client: Support validating IPv6 addresses in CRCX and MDCX commands
* mgcp_client: Deprecate unused IPv4-only API
* mgcp_client: copy back Connection Information from MDCX ACK
* mgw: Fix mgcp_rtp_end field description comment
* mgw: Initial IPv6 support
* mgw: Introduce VTY cmd 'rtp bind-ip-v6' command
* mgw: Find and store RTP conn local_addr once during CRCX handling
* mgw: Announce and rebind new local address if change required during MDCX
* mgw: osmux: Avoid sending packets on recvonly connection
* mgw: Release endpoint after last conn times out
* mgw: osmux: Fix conn watchdog timeout not updated
* mgw: Don't be case-sensitive when parsing X-Osmo-IGN param
* cosmetic: Fix typo in comment
* mgw: Avoid logging notice message each time we receive nt param in LCO
* mgw: Fix return value documentation for API mgcp_verify_call_id
* cosmetic: Fix typo in comment
* contrib/jenkins: Enable parallel make in make distcheck
* .gitignore: Ignore new autofoo tmp files
* tests: Replace deprecated API log_set_print_filename
[ Oliver Smith ]
* contrib: import RPM spec
* contrib: integrate RPM spec
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
* contrib/jenkins: don't build osmo-gsm-manuals
* configure.ac: set -std=gnu11
[ Vadim Yanitskiy ]
* libosmo-mgcp-client: fix use-after-free in mgcp_client_tx()
* libosmo-mgcp-client: fix use-after-free in mgcp_msg_gen()
* libosmo-mgcp: fix unsigned compared against 0 in mgcp_trunk_by_name()
* libosmo-mgcp: fix unused extra argument to printf() in add_fmtp()
* libosmo-mgcp: always check result of msgb_printf() in add_fmtp()
* libosmo-mgcp-client: mgcp_client_tx(): return rc on error
* debian/control: change maintainer to the Osmocom team / mailing list
* vty: use install_lib_element() and install_lib_element_ve()
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
* fixup mgcp_trunk: increase default number of virtual endpoints
[ Alexander Couzens ]
* configure.ac: require libosmoabis + libosmotrau >= 1.0.0
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 18:28:45 +0100
osmo-mgw (1.7.0) unstable; urgency=medium
[ Neels Hofmeyr ]

13
debian/control vendored
View File

@@ -1,14 +1,15 @@
Source: osmo-mgw
Section: net
Priority: extra
Maintainer: Alexander Couzens <lynxis@fe80.eu>
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>=9),
dh-autoreconf,
pkg-config,
autotools-dev,
libosmocore-dev,
libosmo-netif-dev,
osmo-gsm-manuals-dev
libosmocore-dev (>= 1.6.0),
libosmo-netif-dev (>= 1.1.0),
libosmo-abis-dev (>= 1.2.0),
osmo-gsm-manuals-dev (>= 1.2.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
Vcs-Browser: https://git.osmocom.org/osmo-mgw/
@@ -20,7 +21,7 @@ Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-mgcp-client6
Package: libosmo-mgcp-client9
Section: libs
Architecture: any
Multi-Arch: same
@@ -32,7 +33,7 @@ Package: libosmo-mgcp-client-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp-client6 (= ${binary:Version}), ${misc:Depends}
Depends: libosmo-mgcp-client9 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: osmo-mgw-doc

View File

@@ -2,3 +2,4 @@ etc/osmocom/osmo-mgw.cfg
lib/systemd/system/osmo-mgw.service
usr/bin/osmo-mgw
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw.cfg
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw-abis_e1.cfg

View File

@@ -0,0 +1,25 @@
!
! MGCP configuration example
!
e1_input
e1_line 0 driver dahdi
e1_line 0 port 0
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 512
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc
rtp-patch timestamp
trunk 1
rtp keep-alive once
no rtp keep-alive
line 0

View File

@@ -6,11 +6,11 @@ mgcp
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
rtp ip-probing
rtp ip-tos 184
rtp ip-dscp 46
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 31
number endpoints 512
loop 0
force-realloc 1
rtcp-omit

View File

@@ -23,14 +23,13 @@ OsmoMGW(config-mgcp)# local ip 127.0.0.1
=== Configuring the trunk
The first trunk (trunk 0) is considered a virtual trunk in OsmoMGW. All
The first trunk is considered a virtual trunk in OsmoMGW. All
endpoints of type "rtpbridge" are routed here. The virtual trunk is configured
in the config-mgcp context.
All other trunks are configured in the config-mgcp-trunk context, but the
commands used are identical. Right now trunks are considered only for ds/e1
type endpoints which are not yet implemented. Don't use trunks other than the
"virtual" trunk 0.
commands used are identical. Right now trunks are considered only for "ds/e1"
type endpoints.
.Example: MGCP trunk configuration
----
@@ -54,4 +53,72 @@ OsmoMGW(config-mgcp)# rtp-patch timestamp <3>
<2> Hide SSRC changes
<3> Ensure RTP timestamp is aligned with frame duration
NOTE: Changes to trunks that affect resource allocation, such as newly created
trunks or a change of the number of available endpoints, require a full restart
of osmo-mgw!
=== E1 trunk considerations
While the RTP bridge trunks are natively based on IP no special considerations
are required during setup. E1 trunks are mapped on a physical E1 line, which has
to be configured as shown below.
.Example: E1 line setup
----
OsmoMGW(config-e1_input)# e1_line 0 driver dahdi <1>
OsmoMGW(config-e1_input)# e1_line 0 port 2 <2>
----
<1> Name of the libosmo-abis driver implementation ("dahdi")
<2> Port number of the physical E1 port to use (2)
In osmo-mgw the e1_input node is used to configure the physical E1 line. The
line number will be used internally to identify the configured E1 line. The
port number is the physical E1 connector (sometimes called 'span') at the E1
hardware. Per trunk an individual E1 line will be needed. Beware that the E1
driver may also need configuration settings that are not discussed here.
.Example: E1 trunk setup
----
OsmoMGW(config-mgcp)# trunk 0 <1>
OsmoMGW(config-mgcp-trunk)# line 0 <2>
----
<1> Creation of a trunk (0)
<2> Reference to the E1 line to use (0)
The E1 trunk is created along with a number, typically starting at 0, but if
required any number from 0-64 is allowed. The E1 trunk configuration concerning
the IP related aspects is nearly identical to the configuration of the virtual
trunk. However, it is important that the user assigns one of the E1 line numbers
that were configured under the e1_input node.
.Example: A typical configuration with one E1 trunk
----
e1_input
e1_line 0 driver dahdi
e1_line 0 port 2
mgcp
bind ip 127.0.0.1
rtp net-range 6000 6011
rtp net-bind-ip 192.168.100.130
rtp ip-probing
rtp ip-dscp 46
no rtp keep-alive
bind port 2428
number endpoints 30
loop 0
force-realloc 1
osmux off
rtp-patch rfc5993hr
trunk 0
rtp keep-alive once
no rtp keep-alive
line 0
----
NOTE: One E1 trunk always covers a whole E1 line. All subslots (I.640) will be mapped
to individual MGCP endpoints. As long as the endpoints remain unused the
underlying E1 timeslot is not used.
NOTE: The E1 trunk implementation also works with T1 lines, however since T1 has
24 instead of 31 usable timeslots only the endpoints that fall into that 1-24 timeslot
range will be useable.

View File

@@ -0,0 +1,94 @@
== MGCP Endpoints
MGCP organizes the switching resources in so called endpoints. Each endpoint is
referenced by its unique identifier. While RFC 3435 specifies a naming scheme, the
actual identifier naming is subject to the implementation and configuration.
=== RTP proxy / RTP bridge endpoints
OsmoMGW implements a freely configurable number of `rtpbridge` endpoints. Those
endpoints are able to host two connections at a time to model the functionality
of a tandem switch.
RTP bridge endpoint identifiers are referenced by the string `rtpbridge/`, a
hexadecimal number without leading zeros and a domain name (configurable).
----
rtpbridge/<number>@<domain>
----
.Example: List of virtual endpoints
----
rtpbridge/1@mgw
rtpbridge/2@mgw
rtpbridge/3@mgw
rtpbridge/4@mgw
rtpbridge/5@mgw
rtpbridge/6@mgw
rtpbridge/7@mgw
rtpbridge/8@mgw
rtpbridge/9@mgw
rtpbridge/a@mgw
rtpbridge/b@mgw
rtpbridge/c@mgw
rtpbridge/d@mgw
rtpbridge/e@mgw
rtpbridge/f@mgw
rtpbridge/10@mgw
----
=== E1/T1 endpoints
OsmoMGW supports E1 subslot multiplexing as specified by I.460. All possible
subslot combinations are mapped on individual endpoints. The endpoint names
are prefixed with `ds/e1-` followed by the trunk number and the E1 timeslot.
The subslot is defined by a bit rate and a bit offset.
----
ds/e1-<trunk>/s-<timeslot>/su<bitrate>-<bitoffset>@<domain>
----
.Example: List of endpoints on E1 trunk 0 at E1 timeslot 2
----
ds/e1-0/s-2/su64-0@mgw
ds/e1-0/s-2/su32-0@mgw
ds/e1-0/s-2/su32-4@mgw
ds/e1-0/s-2/su16-0@mgw
ds/e1-0/s-2/su16-2@mgw
ds/e1-0/s-2/su16-4@mgw
ds/e1-0/s-2/su16-6@mgw
ds/e1-0/s-2/su8-0@mgw
ds/e1-0/s-2/su8-1@mgw
ds/e1-0/s-2/su8-2@mgw
ds/e1-0/s-2/su8-3@mgw
ds/e1-0/s-2/su8-4@mgw
ds/e1-0/s-2/su8-5@mgw
ds/e1-0/s-2/su8-6@mgw
ds/e1-0/s-2/su8-7@mgw
----
When creating connections on endpoints that reside in one E1 timeslot the call
agent must make sure that no overlapping endpoints are used. It is for example
not possible to use `ds/e1-0/s-2/su16-2@mgw` and `ds/e1-0/s-2/su8-3@mgw` at the
same time because they overlap.
.Subslot overlapping
[options="header"]
|===
| Bit offset 4+| Subslots
| 0 | 8k .2+| 16k .4+| 32k .8+| 64k
| 1 | 8k
| 2 | 8k .2+| 16k
| 3 | 8k
| 4 | 8k .2+| 16k .4+| 32k
| 5 | 8k
| 6 | 8k .2+| 16k
| 7 | 8k
|===
NOTE: The current implementation (December 2020) only implements TRAU frame
encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
not yet useable.
NOTE: the VTY command "show mgcp" can be used to get a list of all available
endpoints (including identifiers)

View File

@@ -21,10 +21,10 @@ Protocol.
digraph G {
rankdir = LR;
OsmoBTS -> OsmoBSC [label="Abis/IP"];
OsmoBSC -> OsmoMSC [label="3GPP AoIP"];
OsmoBSC -> "core-network" [label="3GPP AoIP"];
OsmoBSC -> OsmoMGW [label="MGCP"];
OsmoBTS -> OsmoMGW [label="RTP",dir=both];
OsmoMGW -> OsmoMSC [label="RTP",dir=both];
OsmoMGW -> "core-network" [label="RTP",dir=both];
{rank=same OsmoBSC OsmoMGW}
OsmoMGW [color=red];
}
@@ -36,10 +36,9 @@ digraph G {
----
digraph G {
rankdir = LR;
BTS -> BSC [label="Abis"];
BSC -> OsmoMSC [label="3GPP AoIP"];
"2G BSS" -> OsmoMSC [label="3GPP AoIP"];
OsmoMSC -> OsmoMGW [label="MGCP"];
BSC -> OsmoMGW [label="RTP",dir=both];
"2G BSS" -> OsmoMGW [label="RTP",dir=both];
OsmoMSC -> OsmoSIP [label="MNCC"];
OsmoSIP -> PBX [label="SIP Trunk"];
OsmoMGW -> PBX [label="RTP",dir=both];
@@ -53,6 +52,22 @@ digraph G {
}
----
[[fig-bsc-e1]]
.Integration of legacy E1 BTS in AoIP network
[graphviz]
----
digraph G {
rankdir = LR;
BTS -> OsmoBSC [label="Abis/E1"];
OsmoBSC -> "core-network" [label="3GPP AoIP"];
OsmoBSC -> OsmoMGW [label="MGCP"];
BTS -> OsmoMGW [label="TRAU/E1",dir=both];
OsmoMGW -> "core-network" [label="RTP",dir=both];
{rank=same OsmoBSC OsmoMGW}
OsmoMGW [color=red];
}
----
=== Software Components
OsmoMGW contains a variety of different software components, which well
@@ -77,14 +92,14 @@ Transcoding is currently not supported in OsmoMGW.
=== Limitations
Osmux is not yet supported in OsmoMGW.
At the moment (July 2018), OsmoMGW only implements RTP proxy / RTP bridge
type endpoints, to each of which two RTP connections can be established.
We are planning to add endpoint types for:
At the moment (November 2020), OsmoMGW implements RTP proxy / RTP bridge
type endpoints and E1/T1 16k/8k sub-slots with TRAU frames for classic BTS
support. To the RTP proxy / RTP bridge endpoints two RTP connections can
be established, which then work as a tandem. E1/T1 endpoints support one
RTP connection at a time that is associated with a sub-slot on an E1 line.
We are planning to add further endpoint types for:
- classic E1/T1 timeslots (64kBps alaw/ulaw)
- classic E1/T1 16k sub-slots with TRAU frames for classic BTS support
- announcement/playout end-points
- conference endpoints

View File

@@ -0,0 +1,42 @@
==== Full example of QoS for osmo-mgw
In the below example we will show the full set of configuration required
for both DSCP and PCP differentiation of RTP traffic by osmo-mgw.
What we want to achieve in this example is the following configuration:
.DSCP and PCP assignments for osmo-mgw Abis downlink traffic in this example
[options="header",width="30%",cols="2,1,1"]
|===
|Traffic |DSCP|PCP
|RTP | 46| 6
|===
. configure the osmo-mgw program to set the DSCP value
. configure an egrees QoS map to map from priority to PCP
.Example Step 1: add related VTY configuration to `osmo-mgw.cfg`
----
...
mgcp
rtp ip-dscp 46
rtp socket-priority 6
...
----
.Example Step 2: egress QoS map to map from socket priority to PCP values
----
$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 5:5 6:6 7:7 <2>
----
<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also include the
mapping 5:5 and 7:7 from the osmo-bsc example (see <<userman-osmobsc>>) here.
NOTE:: The settings of the `ip` command are volatile and only active until
the next reboot (or the network device or VLAN is removed). Please refer to
the documentation of your specific Linux distribution in order to find out how
to make such settings persistent by means of an `ifup` hook whenever the interface
comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu,
this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
script.

View File

@@ -18,12 +18,18 @@ include::./common/chapters/logging.adoc[]
include::{srcdir}/chapters/configuration.adoc[]
include::{srcdir}/chapters/mgcp_endpoints.adoc[]
include::{srcdir}/chapters/mgcp_extensions.adoc[]
include::./common/chapters/osmux/osmux.adoc[]
include::./common/chapters/qos-dscp-pcp.adoc[]
//include::{srcdir}/chapters/counters.adoc[]
include::./common/chapters/vty_cpu_sched.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]

View File

@@ -6,6 +6,7 @@ nobase_include_HEADERS = \
osmocom/mgcp_client/mgcp_client.h \
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
osmocom/mgcp_client/mgcp_client_fsm.h \
osmocom/mgcp_client/mgcp_client_pool.h \
osmocom/mgcp/mgcp.h \
osmocom/mgcp/mgcp_common.h \
osmocom/mgcp/osmux.h \

View File

@@ -23,6 +23,7 @@
#pragma once
#include <osmocom/core/msgb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/logging.h>
@@ -33,6 +34,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include "mgcp_ratectr.h"
@@ -61,8 +63,6 @@ struct mgcp_rtp_end;
#define MGCP_POLICY_REJECT 5
#define MGCP_POLICY_DEFER 6
typedef int (*mgcp_change)(struct mgcp_endpoint *endp, int state);
typedef int (*mgcp_policy)(struct mgcp_endpoint *endp, int state, const char *transaction_id);
typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
@@ -93,8 +93,10 @@ typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
* This holds information on how to allocate ports
*/
struct mgcp_port_range {
pthread_mutex_t lock;
/* addr or NULL to fall-back to default */
char *bind_addr;
char bind_addr_v4[INET6_ADDRSTRLEN];
char bind_addr_v6[INET6_ADDRSTRLEN];
/* dynamically allocated */
int range_start;
@@ -127,9 +129,9 @@ enum mgcp_role {
struct mgcp_config {
int source_port;
char *local_ip;
char *source_addr;
char *call_agent_addr;
char local_ip[INET6_ADDRSTRLEN];
char source_addr[INET6_ADDRSTRLEN];
char call_agent_addr[INET6_ADDRSTRLEN];
/* RTP processing */
mgcp_processing rtp_processing_cb;
@@ -141,17 +143,14 @@ struct mgcp_config {
struct mgcp_port_range net_ports;
int endp_dscp;
int endp_priority;
int force_ptime;
mgcp_change change_cb;
mgcp_policy policy_cb;
mgcp_reset reset_cb;
mgcp_rqnt rqnt_cb;
void *data;
uint32_t last_call_id;
/* list holding the trunks */
struct llist_head trunks;
@@ -160,7 +159,7 @@ struct mgcp_config {
/* osmux translator: 0 means disabled, 1 means enabled */
int osmux;
/* addr to bind the server to */
char *osmux_addr;
char osmux_addr[INET6_ADDRSTRLEN];
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
* the osmux socket is already initialized.
*/
@@ -206,5 +205,6 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
int mgcp_send_reset_all(struct mgcp_config *cfg);
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
uint8_t prio);
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);

View File

@@ -21,7 +21,6 @@
static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr);
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
void mgcp_e1_endp_release(struct mgcp_endpoint *endp);

View File

@@ -25,8 +25,9 @@
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/i460_mux.h>
#include <osmocom/mgcp/mgcp_protocol.h>
struct sockaddr_in;
struct sockaddr;
struct mgcp_conn;
struct mgcp_conn_rtp;
struct mgcp_endpoint;
@@ -42,7 +43,7 @@ LOGP(cat, level, "endpoint:%s " fmt, \
struct osmo_rtp_msg_ctx {
int proto;
struct mgcp_conn_rtp *conn_src;
struct sockaddr_in *from_addr;
struct osmo_sockaddr *from_addr;
};
#define OSMO_RTP_MSG_CTX(MSGB) ((struct osmo_rtp_msg_ctx*)(MSGB)->cb)
@@ -96,9 +97,6 @@ struct mgcp_endpoint {
/*! List of struct mgcp_conn, of the connections active on this endpoint */
struct llist_head conns;
/*! Backpointer to the MGW configuration */
struct mgcp_config *cfg;
/*! Backpointer to the trunk this endpoint belongs to */
struct mgcp_trunk *trunk;
@@ -111,10 +109,6 @@ struct mgcp_endpoint {
/*! Last MGCP response (in case re-transmission is required) */
char *last_response;
/*! Memorize if this endpoint was choosen by the MGW (wildcarded, true)
* or if the user has choosen the particular endpoint explicitly. */
bool wildcarded_req;
/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
uint32_t x_osmo_ign;
@@ -134,8 +128,15 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int ind
void mgcp_endp_release(struct mgcp_endpoint *endp);
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
void mgcp_endp_update(struct mgcp_endpoint *endp);
bool mgcp_endp_is_wildcarded(const char *epname);
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
struct mgcp_config *cfg);
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
const struct mgcp_trunk *trunk);
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
const struct mgcp_trunk *trunk);

View File

@@ -25,10 +25,12 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
struct mgcp_conn;
struct mgcp_parse_data;
struct mgcp_endpoint;
struct mgcp_trunk;
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
@@ -39,7 +41,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
int mgcp_parse_osmux_cid(const char *line);
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);

View File

@@ -2,9 +2,21 @@
#include <inttypes.h>
#include <stdbool.h>
#include <osmocom/core/socket.h>
#include <osmocom/mgcp/mgcp.h>
#define MGCP_DUMMY_LOAD 0x23
/* The following constant defines an RTP dummy payload that is used for
* "UDP Hole Punching" (NAT) */
static const char rtp_dummy_payload[] = { 0x23 };
/* Check if the data in a given message buffer matches the rtp dummy payload
* defined above */
#define mgcp_is_rtp_dummy_payload(msg) \
(msgb_length(msg) == sizeof(rtp_dummy_payload) && \
memcmp(msgb_data(msg), rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0)
#define RTP_BUF_SIZE 4096
struct mgcp_rtp_stream_state {
@@ -22,7 +34,7 @@ struct mgcp_rtp_state {
struct {
/* are we patching the SSRC value? */
int patch_ssrc;
bool patch_ssrc;
/* original SSRC (to which we shall patch any different SSRC) */
uint32_t orig_ssrc;
/* offset to apply on the sequence number */
@@ -69,8 +81,8 @@ struct mgcp_rtp_codec {
uint32_t frame_duration_den;
int payload_type;
char *audio_name;
char *subtype_name;
char audio_name[64];
char subtype_name[64];
bool param_present;
struct mgcp_codec_param param;
@@ -78,8 +90,8 @@ struct mgcp_rtp_codec {
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
struct mgcp_rtp_end {
/* local IP address of the RTP socket */
struct in_addr addr;
/* remote IP address of the RTP socket */
struct osmo_sockaddr addr;
/* in network byte order */
int rtp_port, rtcp_port;
@@ -115,18 +127,23 @@ struct mgcp_rtp_end {
/* local UDP port number of the RTP socket; RTCP is +1 */
int local_port;
/* where the endpoint RTP connection binds to, set during CRCX and
* possibly updated during MDCX */
char local_addr[INET6_ADDRSTRLEN];
};
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
struct mgcp_rtp_tap {
/* is this tap active (1) or not (0) */
int enabled;
/* IP/port to which we're forwarding the tapped data */
struct sockaddr_in forward;
struct osmo_sockaddr forward;
};
struct mgcp_conn;
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst);
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
@@ -137,12 +154,11 @@ void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *con
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
struct mgcp_conn_rtp *conn);
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct sockaddr_in *addr, struct msgb *msg);
struct osmo_sockaddr *addr, struct msgb *msg);
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
int mgcp_set_ip_tos(int fd, int tos);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
@@ -158,6 +174,6 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn);
/* internal RTP Annex A counting */
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
const uint16_t seq, const int32_t transit,
const uint32_t ssrc);
const uint32_t ssrc, const bool marker_bit);

View File

@@ -3,7 +3,7 @@
/* Internal structure while parsing a request */
struct mgcp_parse_data {
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
char *epname;
char *trans;
char *save;
};
@@ -16,12 +16,15 @@ struct mgcp_lco {
int pkt_period_max; /* time in ms */
};
char *mgcp_debug_get_last_endpoint_name(void);
char *get_lco_identifier(const char *options);
int check_local_cx_options(void *ctx, const char *options);
struct mgcp_rtp_end;
struct mgcp_endpoint;
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
struct mgcp_rtp_end *rtp);
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *rtp);
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
const struct mgcp_rtp_end *rtp);

View File

@@ -1,6 +1,5 @@
#pragma once
/* Global MCGP general rate counters */
enum {
MGCP_GENERAL_RX_MSGS_TOTAL,
@@ -23,7 +22,6 @@ enum {
MGCP_CRCX_FAIL_ALLOC_CONN,
MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
MGCP_CRCX_FAIL_START_RTP,
MGCP_CRCX_FAIL_REJECTED_BY_POLICY,
MGCP_CRCX_FAIL_NO_OSMUX,
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
@@ -46,21 +44,16 @@ enum {
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
MGCP_MDCX_FAIL_START_RTP,
MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
MGCP_MDCX_DEFERRED_BY_POLICY,
MGCP_MDCX_FAIL_AVAIL,
};
/* Trunk-global MCGP DLCX related rate counters */
enum {
MGCP_DLCX_SUCCESS,
MGCP_DLCX_FAIL_WILDCARD,
MGCP_DLCX_FAIL_NO_CONN,
MGCP_DLCX_FAIL_INVALID_CALLID,
MGCP_DLCX_FAIL_INVALID_CONNID,
MGCP_DLCX_FAIL_UNHANDLED_PARAM,
MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
MGCP_DLCX_DEFERRED_BY_POLICY,
MGCP_DLCX_FAIL_AVAIL,
};
@@ -91,5 +84,24 @@ struct mgcp_ratectr_trunk {
struct rate_ctr_group *e1_stats;
};
int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr);
int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr);
struct mgcp_config;
struct mgcp_trunk;
int mgcp_ratectr_global_alloc(struct mgcp_config *cfg);
void mgcp_ratectr_global_free(struct mgcp_config *cfg);
int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk);
void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk);
/* Trunk-global common stat items */
enum {
TRUNK_STAT_ENDPOINTS_TOTAL,
TRUNK_STAT_ENDPOINTS_USED,
};
struct mgcp_stat_trunk {
/* Stat item group which contains general status values of the trunk. */
struct osmo_stat_item_group *common;
};
int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk);
void mgcp_stat_trunk_free(struct mgcp_trunk *trunk);

View File

@@ -1,30 +1,35 @@
#pragma once
#include <osmocom/gsm/i460_mux.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/mgcp/mgcp_ratectr.h>
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
LOGP(cat, level, "trunk:%u " fmt, \
trunk ? trunk->trunk_nr : 0, \
## args)
enum mgcp_trunk_type {
MGCP_TRUNK_VIRTUAL,
MGCP_TRUNK_E1,
};
extern const struct value_string mgcp_trunk_type_strs[];
static inline const char *mgcp_trunk_type_strs_str(enum mgcp_trunk_type val)
{ return get_value_string(mgcp_trunk_type_strs, val); }
struct mgcp_trunk {
struct llist_head entry;
struct mgcp_config *cfg;
int trunk_nr;
unsigned int trunk_nr;
enum mgcp_trunk_type trunk_type;
char *audio_fmtp_extra;
int audio_send_ptime;
int audio_send_name;
int audio_loop;
int no_audio_transcoding;
@@ -49,8 +54,9 @@ struct mgcp_trunk {
unsigned int number_endpoints;
struct mgcp_endpoint **endpoints;
/* global rate counters to measure the trunks overall performance and health */
/* rate counters and stat items to measure the trunks overall performance and health */
struct mgcp_ratectr_trunk ratectr;
struct mgcp_stat_trunk stats;
union {
/* Virtual trunk specific */
@@ -60,18 +66,20 @@ struct mgcp_trunk {
/* E1 specific */
struct {
unsigned int vty_line_nr;
struct e1inp_line *line;
bool ts_in_use[31];
struct osmo_i460_timeslot i460_ts[31];
bool ts_in_use[NUM_E1_TS-1];
struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
/* Note: on an E1 line TS 0 is devoted to framing and
* alignment and therefore only NUM_E1_TS-1 timeslots
* are available for traffic. */
} e1;
};
};
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
int mgcp_trunk_equip(struct mgcp_trunk *trunk);
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
int e1_trunk_nr_from_epname(const char *epname);
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
/* The virtual trunk is always created on trunk id 0 for historical reasons,

View File

@@ -1,5 +1,6 @@
#pragma once
#include <osmocom/core/socket.h>
#include <osmocom/netif/osmux.h>
struct mgcp_conn_rtp;
@@ -13,7 +14,7 @@ enum {
int osmux_init(int role, struct mgcp_config *cfg);
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
struct in_addr *addr, uint16_t port);
struct osmo_sockaddr *addr, uint16_t port);
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);

View File

@@ -6,3 +6,7 @@ enum mgcp_vty_node {
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
TRUNK_NODE,
};
enum mgw_vty_cmd_attr {
MGW_CMD_ATTR_NEWCONN = 0,
};

View File

@@ -4,6 +4,7 @@ BUILT_SOURCES = \
noinst_HEADERS = \
mgcp_client_internal.h \
mgcp_client_pool_internal.h \
$(NULL)
mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h

View File

@@ -6,7 +6,7 @@
#include <osmocom/mgcp_client/mgcp_common.h>
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
@@ -26,6 +26,15 @@ struct mgcp_client_conf {
/* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.
* If this is nonempty, the contained name will be used instead of 'mgw'. */
char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
/* The user may configure certain endpoint names that are reset via DLCX
* on startup. Usually this will be one wildcarded endpoint e.g.
* 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.
* 'ds/e1-0/s-3/su16-4' */
struct llist_head reset_epnames;
/* human readable name / description */
char *description;
};
typedef unsigned int mgcp_trans_id_t;
@@ -75,7 +84,7 @@ struct mgcp_response {
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
char audio_ip[INET_ADDRSTRLEN];
char audio_ip[INET6_ADDRSTRLEN];
unsigned int ptime;
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
unsigned int codecs_len;
@@ -130,10 +139,12 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
struct mgcp_client *mgcp_client_init(void *ctx,
struct mgcp_client_conf *conf);
int mgcp_client_connect(struct mgcp_client *mgcp);
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
void mgcp_client_disconnect(struct mgcp_client *mgcp);
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp);
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp) OSMO_DEPRECATED("deprecated, returns 0");
const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp);
const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
@@ -165,3 +176,5 @@ unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
enum mgcp_codecs codec);
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
unsigned int pt);
const char *mgcp_client_name(const struct mgcp_client *mgcp);

View File

@@ -23,6 +23,8 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);
bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid);
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_remote_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
struct osmo_fsm_inst *notify,
@@ -45,6 +47,7 @@ void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
extern const struct value_string osmo_mgcp_verb_names[];
static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)

View File

@@ -8,14 +8,14 @@
* (either remote or local). It is used to pass parameters (local) to the FSM
* and get responses (remote) from the FSM as pointer attached to the FSM
* event.
*
*
* When modifiying a connection, the endpoint and call_id members may be left
* unpopulated. The call_id field is ignored in this case. If an endpoint
* identifier is supplied it is checked against the internal state to make
* sure it is correct. */
struct mgcp_conn_peer {
/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
char addr[INET_ADDRSTRLEN];
char addr[INET6_ADDRSTRLEN];
/*! RTP connection IP-Port (optional) */
uint16_t port;
@@ -69,5 +69,6 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);

View File

@@ -4,13 +4,19 @@
#define MSGB_CB_MGCP_TRANS_ID 0
/* Struct that holds one endpoint name */
struct reset_ep {
struct llist_head list;
char name[MGCP_ENDPOINT_MAXLEN];
};
struct mgcp_client {
struct mgcp_client_conf actual;
uint32_t remote_addr;
struct osmo_wqueue wq;
mgcp_trans_id_t next_trans_id;
struct llist_head responses_pending;
struct llist_head inuse_endpoints;
struct mgcp_client_pool *pool;
};
struct mgcp_inuse_endpoint {

View File

@@ -0,0 +1,11 @@
#pragma once
struct mgcp_client;
struct mgcp_client_pool;
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);

View File

@@ -0,0 +1,45 @@
#pragma once
/* Struct to handle a member of a pool of MGWs. */
struct mgcp_client_pool_member {
struct llist_head list;
/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
* the log. */
unsigned int nr;
/* MGCP client configuration, this is not the running configuration, when mgcp_client_init() is executed, a
* copy of this config is created. */
struct mgcp_client_conf conf;
/* MGCP client descriptor, will be automatically allocated when mgcp_client_pool_connect() is called. (the MGCP
* client is connected when this pointer is populated) */
struct mgcp_client *client;
/* A pool member may be set as 'blocked' from the VTY, this means that the pool member may still work and serve
* ongoing calls, but it won't be picked from the pool anymore. */
bool blocked;
/* Reference counter to count how often this pool member is currently picked. */
unsigned int refcount;
};
/* Struct to handle a pool of MGWs. (Use _pool functions) */
struct mgcp_client_pool {
/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
* mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
struct mgcp_client *mgcp_client_single;
/* A list that manages the pool members (see above) */
struct llist_head pool;
/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
* mgcp_client_pool_vty_init() */
char *vty_indent;
/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
struct cmd_node *vty_node;
};
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);

View File

@@ -9,6 +9,7 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -20,7 +21,7 @@ AM_LDFLAGS = \
# This is not at all related to the release version, but a range of supported
# API versions. Read TODO_RELEASE in the source tree's root!
MGCP_CLIENT_LIBVERSION=7:0:1
MGCP_CLIENT_LIBVERSION=9:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
@@ -31,6 +32,7 @@ libosmo_mgcp_client_la_SOURCES = \
mgcp_client_vty.c \
mgcp_client_fsm.c \
mgcp_client_endpoint_fsm.c \
mgcp_client_pool.c \
$(NULL)
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)

View File

@@ -25,10 +25,13 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/abis/e1_input.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -43,6 +46,9 @@
#define OSMUX_CID_MAX 255 /* FIXME: use OSMUX_CID_MAX from libosmo-netif? */
#endif
#define LOGPMGW(mgcp, level, fmt, args...) \
LOGP(DLMGCP, level, "MGW(%s) " fmt, mgcp_client_name(mgcp), ## args)
/* Codec descripton for dynamic payload types (SDP) */
const struct value_string osmo_mgcpc_codec_names[] = {
{ CODEC_PCMU_8000_1, "PCMU/8000/1" },
@@ -66,7 +72,6 @@ static char *extract_codec_name(const char *str)
if (!str)
return NULL;
/* FIXME osmo_strlcpy */
osmo_strlcpy(buf, str, sizeof(buf));
for (i = 0; i < strlen(buf); i++) {
@@ -187,7 +192,7 @@ enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
return pt;
}
/*! Initalize MGCP client configuration struct with default values.
/*! Initialize MGCP client configuration struct with default values.
* \param[out] conf Client configuration.*/
void mgcp_client_conf_init(struct mgcp_client_conf *conf)
{
@@ -198,6 +203,8 @@ void mgcp_client_conf_init(struct mgcp_client_conf *conf)
.remote_addr = NULL,
.remote_port = -1,
};
INIT_LLIST_HEAD(&conf->reset_epnames);
}
static void mgcp_client_handle_response(struct mgcp_client *mgcp,
@@ -205,14 +212,13 @@ static void mgcp_client_handle_response(struct mgcp_client *mgcp,
struct mgcp_response *response)
{
if (!pending) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot handle NULL response\n");
LOGPMGW(mgcp, LOGL_ERROR, "Cannot handle NULL response\n");
return;
}
if (pending->response_cb)
pending->response_cb(response, pending->priv);
else
LOGP(DLMGCP, LOGL_DEBUG, "MGCP response ignored (NULL cb)\n");
LOGPMGW(mgcp, LOGL_DEBUG, "MGCP response ignored (NULL cb)\n");
talloc_free(pending);
}
@@ -370,22 +376,37 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
/* Parse a line like "c=IN IP4 10.11.12.13" */
static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
{
struct in_addr ip_test;
struct in6_addr ip_test;
bool is_ipv6;
if (strlen(line) < 16)
if (strncmp("c=IN IP", line, 7) != 0)
goto response_parse_failure;
/* The current implementation strictly supports IPV4 only ! */
if (memcmp("c=IN IP4 ", line, 9) != 0)
line += 7;
if (*line == '6')
is_ipv6 = true;
else if (*line == '4')
is_ipv6 = false;
else
goto response_parse_failure;
/* Extract IP-Address */
osmo_strlcpy(r->audio_ip, line + 9, sizeof(r->audio_ip));
/* Check IP-Address */
if (inet_aton(r->audio_ip, &ip_test) == 0)
line++;
if (*line != ' ')
goto response_parse_failure;
line++;
/* Extract and check IP-Address */
if (is_ipv6) {
/* 45 = INET6_ADDRSTRLEN -1 */
if (sscanf(line, "%45s", r->audio_ip) != 1)
goto response_parse_failure;
if (inet_pton(AF_INET6, r->audio_ip, &ip_test) != 1)
goto response_parse_failure;
} else {
/* 15 = INET_ADDRSTRLEN -1 */
if (sscanf(line, "%15s", r->audio_ip) != 1)
goto response_parse_failure;
if (inet_pton(AF_INET, r->audio_ip, &ip_test) != 1)
goto response_parse_failure;
}
return 0;
response_parse_failure:
@@ -654,23 +675,25 @@ int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
rc = mgcp_response_parse_head(r, msg);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
rc = 1;
goto error;
}
LOGPMGW(mgcp, LOGL_DEBUG, "MGCP client: Rx %d %u %s\n",
r->head.response_code, r->head.trans_id, r->head.comment);
rc = parse_head_params(r);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
LOGPMGW(mgcp, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
rc = 1;
goto error;
}
pending = mgcp_client_response_pending_get(mgcp, r->head.trans_id);
if (!pending) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find matching MGCP transaction for trans_id %d\n",
r->head.trans_id);
LOGPMGW(mgcp, LOGL_ERROR, "Cannot find matching MGCP transaction for trans_id %d\n",
r->head.trans_id);
rc = -ENOENT;
goto error;
}
@@ -691,19 +714,19 @@ static int mgcp_do_read(struct osmo_fd *fd)
msg = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
if (!msg) {
LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
LOGPMGW(mgcp, LOGL_ERROR, "Failed to allocate MGCP message.\n");
return -1;
}
ret = read(fd->fd, msg->data, 4096 - 128);
if (ret <= 0) {
LOGP(DLMGCP, LOGL_ERROR, "Failed to read: %s: %d='%s'\n", osmo_sock_get_name2(fd->fd),
errno, strerror(errno));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n",
osmo_sock_get_name2(fd->fd), errno, strerror(errno));
msgb_free(msg);
return -1;
} else if (ret > 4096 - 128) {
LOGP(DLMGCP, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
LOGPMGW(mgcp, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
msgb_free(msg);
return -1;
}
@@ -717,15 +740,17 @@ static int mgcp_do_read(struct osmo_fd *fd)
static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
{
int ret;
struct mgcp_client *mgcp = fd->data;
LOGP(DLMGCP, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
osmo_sock_get_name2(fd->fd), msg->len, osmo_escape_str((const char*)msg->data, OSMO_MIN(42, msg->len)));
LOGPMGW(mgcp, LOGL_DEBUG, "Tx MGCP: %s: len=%u '%s'...\n",
osmo_sock_get_name2(fd->fd), msg->len,
osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
ret = write(fd->fd, msg->data, msg->len);
if (ret != msg->len)
LOGP(DLMGCP, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
osmo_sock_get_name2(fd->fd), errno, strerror(errno),
msg->len, osmo_escape_str((const char*)msg->data, OSMO_MIN(42, msg->len)));
LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n",
osmo_sock_get_name2(fd->fd), errno, strerror(errno),
msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len)));
return ret;
}
@@ -733,6 +758,8 @@ struct mgcp_client *mgcp_client_init(void *ctx,
struct mgcp_client_conf *conf)
{
struct mgcp_client *mgcp;
struct reset_ep *reset_ep;
struct reset_ep *actual_reset_ep;
mgcp = talloc_zero(ctx, struct mgcp_client);
if (!mgcp)
@@ -756,88 +783,144 @@ struct mgcp_client *mgcp_client_init(void *ctx,
if (osmo_strlcpy(mgcp->actual.endpoint_domain_name, conf->endpoint_domain_name,
sizeof(mgcp->actual.endpoint_domain_name))
>= sizeof(mgcp->actual.endpoint_domain_name)) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP client: endpoint domain name is too long, max length is %zu: '%s'\n",
sizeof(mgcp->actual.endpoint_domain_name) - 1, conf->endpoint_domain_name);
LOGPMGW(mgcp, LOGL_ERROR, "MGCP client: endpoint domain name is too long, max length is %zu: '%s'\n",
sizeof(mgcp->actual.endpoint_domain_name) - 1, conf->endpoint_domain_name);
talloc_free(mgcp);
return NULL;
}
LOGP(DLMGCP, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));
LOGPMGW(mgcp, LOGL_NOTICE, "MGCP client: using endpoint domain '@%s'\n", mgcp_client_endpoint_domain(mgcp));
INIT_LLIST_HEAD(&mgcp->actual.reset_epnames);
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
actual_reset_ep = talloc_memdup(mgcp, reset_ep, sizeof(*reset_ep));
llist_add_tail(&actual_reset_ep->list, &mgcp->actual.reset_epnames);
}
if (conf->description)
mgcp->actual.description = talloc_strdup(mgcp, conf->description);
return mgcp;
}
static int init_socket(struct mgcp_client *mgcp)
static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)
{
int rc;
struct osmo_wqueue *wq;
int i;
unsigned int i;
wq = &mgcp->wq;
for (i = 0; i < 100; i++) {
for (i = 0; i < retry_n_ports + 1; i++) {
/* Initalize socket with the currently configured port
* number */
rc = osmo_sock_init2_ofd(&wq->bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
/* 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 choosen
* that port conciously and we will not try to resolve
* this by silently choosing a different port. */
/* 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;
/* Choose a new port number to try next */
LOGP(DLMGCP, LOGL_NOTICE,
"MGCPGW failed to bind to %s:%u, retrying with port %u\n",
mgcp->actual.local_addr, mgcp->actual.local_port, mgcp->actual.local_port + 1);
mgcp->actual.local_port++;
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++;
}
}
LOGP(DLMGCP, LOGL_FATAL, "MGCPGW failed to find a port to bind on %i times.\n", i);
LOGPMGW(mgcp, LOGL_FATAL, "Failed to find a port to bind on %u times -- check configuration!\n", i);
return -EINVAL;
}
/*! Initalize client connection (opens socket only, no request is sent yet)
* \param[in,out] mgcp MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
int mgcp_client_connect(struct mgcp_client *mgcp)
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
/* Format DLCX message (fire and forget) and send it off to the MGW */
static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname)
{
struct sockaddr_in addr;
struct osmo_wqueue *wq;
struct msgb *msgb_dlcx;
struct mgcp_msg mgcp_msg_dlcx = {
.verb = MGCP_VERB_DLCX,
.presence = MGCP_MSG_PRESENCE_ENDPOINT,
};
osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint));
msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx);
mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL);
}
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, const char *name)
{
static char endpoint[MGCP_ENDPOINT_MAXLEN];
int rc;
rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
if (rc > sizeof(endpoint) - 1) {
LOGPMGW(mgcp, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
return NULL;
}
if (rc < 1) {
LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
return NULL;
}
return endpoint;
}
/*! Initialize client connection (opens socket)
* \param[in,out] mgcp MGCP client descriptor.
* \param[in] 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)
{
struct osmo_wqueue *wq;
int rc;
struct reset_ep *reset_ep;
const char *epname;
if (!mgcp) {
LOGP(DLMGCP, LOGL_FATAL, "MGCPGW client not initialized properly\n");
LOGPMGW(mgcp, LOGL_FATAL, "Client not initialized properly\n");
return -EINVAL;
}
wq = &mgcp->wq;
rc = init_socket(mgcp);
if (rc < 0) {
LOGP(DLMGCP, LOGL_FATAL,
"Failed to initialize socket %s:%u -> %s:%u for MGCP GW: %s\n",
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port, strerror(errno));
goto error_close_fd;
}
inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
osmo_wqueue_init(wq, 1024);
wq->bfd.when = OSMO_FD_READ;
wq->bfd.data = mgcp;
wq->read_cb = mgcp_do_read;
wq->write_cb = mgcp_do_write;
LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
rc = init_socket(mgcp, retry_n_ports);
if (rc < 0) {
LOGPMGW(mgcp, LOGL_FATAL,
"Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
mgcp->actual.remote_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.remote_port,
strerror(errno));
goto error_close_fd;
}
LOGPMGW(mgcp, LOGL_INFO, "MGW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
/* If configured, send a DLCX message to the endpoints that are configured to
* be reset on startup. Usually this is a wildcarded endpoint. */
llist_for_each_entry(reset_ep, &mgcp->actual.reset_epnames, list) {
epname = _mgcp_client_name_append_domain(mgcp, reset_ep->name);
LOGPMGW(mgcp, LOGL_INFO, "Sending DLCX to: %s\n", epname);
_mgcp_client_send_dlcx(mgcp, epname);
}
return 0;
error_close_fd:
close(wq->bfd.fd);
@@ -845,6 +928,35 @@ error_close_fd:
return rc;
}
/*! Initialize client connection (opens socket)
* \param[in,out] mgcp MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
int mgcp_client_connect(struct mgcp_client *mgcp)
{
return mgcp_client_connect2(mgcp, 99);
}
/*! Terminate client connection
* \param[in,out] mgcp MGCP client descriptor.
* \returns 0 on success, -EINVAL on error. */
void mgcp_client_disconnect(struct mgcp_client *mgcp)
{
struct osmo_wqueue *wq;
if (!mgcp) {
LOGP(DLMGCP, LOGL_FATAL, "MGCP client not initialized properly\n");
return;
}
wq = &mgcp->wq;
osmo_wqueue_clear(wq);
LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_sock_get_name2(wq->bfd.fd));
close(wq->bfd.fd);
wq->bfd.fd = -1;
if (osmo_fd_is_registered(&wq->bfd))
osmo_fd_unregister(&wq->bfd);
}
/*! Get the IP-Aaddress of the associated MGW as string.
* \param[in] mgcp MGCP client descriptor.
* \returns a pointer to the address string. */
@@ -861,12 +973,13 @@ uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp)
return mgcp->actual.remote_port;
}
/*! Get the IP-Aaddress of the associated MGW as its numeric representation.
/*! Get the IP-Address of the associated MGW as its numeric representation.
* DEPRECATED, DON'T USE.
* \param[in] mgcp MGCP client descriptor.
* \returns IP-Address as 32 bit integer (network byte order) */
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
{
return mgcp->remote_addr;
return 0;
}
/* To compose endpoint names, usually for CRCX, use this as domain name.
@@ -876,24 +989,6 @@ const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp)
return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
}
static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)
{
static char endpoint[MGCP_ENDPOINT_MAXLEN];
int rc;
rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
if (rc > sizeof(endpoint) - 1) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
return NULL;
}
if (rc < 1) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP endpoint name\n");
return NULL;
}
return endpoint;
}
/*! Compose endpoint name for a wildcarded request to the virtual trunk
* \param[in] mgcp MGCP client descriptor.
* \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */
@@ -925,7 +1020,7 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
talloc_asprintf(ctx, "ds/e1-%u/s-%u/su%u-%u@%s", trunk_id, ts, rate, offset,
mgcp_client_endpoint_domain(mgcp));
if (!epname) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP e1-endpoint name!\n");
LOGPMGW(mgcp, LOGL_ERROR, "Cannot compose MGCP e1-endpoint name!\n");
return NULL;
}
@@ -935,18 +1030,19 @@ const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uin
rate_offs_valid = true;
}
if (!rate_offs_valid) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot compose MGCP e1-endpoint name (%s), rate(%u)/offset(%u) combination is invalid!\n", epname,
rate, offset);
LOGPMGW(mgcp, LOGL_ERROR,
"Cannot compose MGCP e1-endpoint name (%s), rate(%u)/offset(%u) combination is invalid!\n",
epname, rate, offset);
talloc_free(epname);
return NULL;
}
/* An E1 line has a maximum of 32 timeslots, while the first (ts=0) is
* reserverd for framing and alignment, so we can not use it here. */
if (ts == 0 || ts > 31) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot compose MGCP e1-endpoint name (%s), E1-timeslot number (%u) is invalid!\n", epname, ts);
if (ts == 0 || ts > NUM_E1_TS-1) {
LOGPMGW(mgcp, LOGL_ERROR,
"Cannot compose MGCP e1-endpoint name (%s), E1-timeslot number (%u) is invalid!\n",
epname, ts);
talloc_free(epname);
return NULL;
}
@@ -974,7 +1070,7 @@ struct mgcp_response_pending * mgcp_client_pending_add(
return pending;
}
/* Send the MGCP message in msg to the MGCP GW and handle a response with
/* Send the MGCP message in msg to the MGW and handle a response with
* response_cb. NOTE: the response_cb still needs to call
* mgcp_response_parse_params(response) to get the parsed parameters -- to
* potentially save some CPU cycles, only the head line has been parsed when
@@ -991,8 +1087,8 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
trans_id = msg->cb[MSGB_CB_MGCP_TRANS_ID];
if (!trans_id) {
LOGP(DLMGCP, LOGL_ERROR,
"Unset transaction id in mgcp send request\n");
LOGPMGW(mgcp, LOGL_ERROR,
"Unset transaction id in mgcp send request\n");
talloc_free(msg);
return -EINVAL;
}
@@ -1007,9 +1103,9 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
}
if (msgb_l2len(msg) > 4096) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot send, MGCP message too large: %u\n",
msgb_l2len(msg));
LOGPMGW(mgcp, LOGL_ERROR,
"Cannot send, MGCP message too large: %u\n",
msgb_l2len(msg));
msgb_free(msg);
rc = -EINVAL;
goto mgcp_tx_error;
@@ -1017,12 +1113,12 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
rc = osmo_wqueue_enqueue(&mgcp->wq, msg);
if (rc) {
LOGP(DLMGCP, LOGL_FATAL, "Could not queue message to MGCP GW\n");
LOGPMGW(mgcp, LOGL_FATAL, "Could not queue message to MGW\n");
msgb_free(msg);
goto mgcp_tx_error;
} else
LOGP(DLMGCP, LOGL_DEBUG, "Queued %u bytes for MGCP GW\n",
msgb_l2len(msg));
LOGPMGW(mgcp, LOGL_DEBUG, "Queued %u bytes for MGW\n",
msgb_l2len(msg));
return 0;
mgcp_tx_error:
@@ -1049,10 +1145,10 @@ int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id)
struct mgcp_response_pending *pending = mgcp_client_response_pending_get(mgcp, trans_id);
if (!pending) {
/*! Note: it is not harmful to cancel a transaction twice. */
LOGP(DLMGCP, LOGL_ERROR, "Cannot cancel, no such transaction: %u\n", trans_id);
LOGPMGW(mgcp, LOGL_ERROR, "Cannot cancel, no such transaction: %u\n", trans_id);
return -ENOENT;
}
LOGP(DLMGCP, LOGL_DEBUG, "Canceled transaction %u\n", trans_id);
LOGPMGW(mgcp, LOGL_DEBUG, "Canceled transaction %u\n", trans_id);
talloc_free(pending);
return 0;
/*! We don't really need to clean up the wqueue: In all sane cases, the msgb has already been sent
@@ -1090,30 +1186,40 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
const char *codec;
unsigned int pt;
rc += msgb_printf(msg, "L:");
rc |= msgb_printf(msg, "L:");
if (mgcp_msg->ptime)
rc += msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
rc |= msgb_printf(msg, " p:%u,", mgcp_msg->ptime);
if (mgcp_msg->codecs_len) {
rc += msgb_printf(msg, " a:");
rc |= msgb_printf(msg, " a:");
for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = mgcp_msg->codecs[i];
codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
/* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */
OSMO_ASSERT(codec);
rc += msgb_printf(msg, "%s", extract_codec_name(codec));
if (!codec) {
msgb_free(msg);
return -EINVAL;
}
rc |= msgb_printf(msg, "%s", extract_codec_name(codec));
if (i < mgcp_msg->codecs_len - 1)
rc += msgb_printf(msg, ";");
rc |= msgb_printf(msg, ";");
}
rc += msgb_printf(msg, ",");
rc |= msgb_printf(msg, ",");
}
rc += msgb_printf(msg, " nt:IN\r\n");
rc |= msgb_printf(msg, " nt:IN\r\n");
return rc;
if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"message buffer to small, can not generate MGCP message (LCO)\n");
msgb_free(msg);
return -ENOBUFS;
}
return 0;
}
/* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */
@@ -1121,56 +1227,70 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
{
unsigned int i;
int rc = 0;
char local_ip[INET_ADDRSTRLEN];
char local_ip[INET6_ADDRSTRLEN];
int local_ip_family, audio_ip_family;
const char *codec;
unsigned int pt;
/* Add separator to mark the beginning of the SDP block */
rc += msgb_printf(msg, "\r\n");
rc |= msgb_printf(msg, "\r\n");
/* Add SDP protocol version */
rc += msgb_printf(msg, "v=0\r\n");
rc |= msgb_printf(msg, "v=0\r\n");
/* Determine local IP-Address */
if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Could not determine local IP-Address!\n");
LOGPMGW(mgcp, LOGL_ERROR,
"Could not determine local IP-Address!\n");
msgb_free(msg);
return -2;
return -EINVAL;
}
local_ip_family = osmo_ip_str_type(local_ip);
if (local_ip_family == AF_UNSPEC) {
msgb_free(msg);
return -EINVAL;
}
audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
if (audio_ip_family == AF_UNSPEC) {
msgb_free(msg);
return -EINVAL;
}
/* Add owner/creator (SDP) */
rc += msgb_printf(msg, "o=- %x 23 IN IP4 %s\r\n",
mgcp_msg->call_id, local_ip);
rc |= msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
local_ip_family == AF_INET6 ? '6' : '4',
local_ip);
/* Add session name (none) */
rc += msgb_printf(msg, "s=-\r\n");
rc |= msgb_printf(msg, "s=-\r\n");
/* Add RTP address and port */
if (mgcp_msg->audio_port == 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
msgb_free(msg);
return -2;
return -EINVAL;
}
if (strlen(mgcp_msg->audio_ip) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty ip address, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR,
"Empty ip address, can not generate MGCP message\n");
msgb_free(msg);
return -2;
return -EINVAL;
}
rc += msgb_printf(msg, "c=IN IP4 %s\r\n", mgcp_msg->audio_ip);
rc |= msgb_printf(msg, "c=IN IP%c %s\r\n",
audio_ip_family == AF_INET6 ? '6' : '4',
mgcp_msg->audio_ip);
/* Add time description, active time (SDP) */
rc += msgb_printf(msg, "t=0 0\r\n");
rc |= msgb_printf(msg, "t=0 0\r\n");
rc += msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
rc |= msgb_printf(msg, "m=audio %u RTP/AVP", mgcp_msg->audio_port);
for (i = 0; i < mgcp_msg->codecs_len; i++) {
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
rc += msgb_printf(msg, " %u", pt);
rc |= msgb_printf(msg, " %u", pt);
}
rc += msgb_printf(msg, "\r\n");
rc |= msgb_printf(msg, "\r\n");
/* Add optional codec parameters (fmtp) */
if (mgcp_msg->param_present) {
@@ -1180,9 +1300,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
continue;
pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
rc += msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
rc |= msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
rc += msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
rc |= msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
}
}
@@ -1197,16 +1317,25 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
/* Note: Use codec descriptors from enum mgcp_codecs
* in mgcp_client only! */
OSMO_ASSERT(codec);
if (!codec) {
msgb_free(msg);
return -EINVAL;
}
rc += msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
rc |= msgb_printf(msg, "a=rtpmap:%u %s\r\n", pt, codec);
}
}
if (mgcp_msg->ptime)
rc += msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
rc |= msgb_printf(msg, "a=ptime:%u\r\n", mgcp_msg->ptime);
return rc;
if (rc != 0) {
LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message (SDP)\n");
msgb_free(msg);
return -ENOBUFS;
}
return 0;
}
/*! Generate an MGCP message
@@ -1219,7 +1348,6 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
uint32_t mandatory_mask;
struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
int rc = 0;
int rc_sdp;
bool use_sdp = false;
char buf[32];
@@ -1230,35 +1358,34 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
switch (mgcp_msg->verb) {
case MGCP_VERB_CRCX:
mandatory_mask = MGCP_CRCX_MANDATORY;
rc += msgb_printf(msg, "CRCX %u", trans_id);
rc |= msgb_printf(msg, "CRCX %u", trans_id);
break;
case MGCP_VERB_MDCX:
mandatory_mask = MGCP_MDCX_MANDATORY;
rc += msgb_printf(msg, "MDCX %u", trans_id);
rc |= msgb_printf(msg, "MDCX %u", trans_id);
break;
case MGCP_VERB_DLCX:
mandatory_mask = MGCP_DLCX_MANDATORY;
rc += msgb_printf(msg, "DLCX %u", trans_id);
rc |= msgb_printf(msg, "DLCX %u", trans_id);
break;
case MGCP_VERB_AUEP:
mandatory_mask = MGCP_AUEP_MANDATORY;
rc += msgb_printf(msg, "AUEP %u", trans_id);
rc |= msgb_printf(msg, "AUEP %u", trans_id);
break;
case MGCP_VERB_RSIP:
mandatory_mask = MGCP_RSIP_MANDATORY;
rc += msgb_printf(msg, "RSIP %u", trans_id);
rc |= msgb_printf(msg, "RSIP %u", trans_id);
break;
default:
LOGP(DLMGCP, LOGL_ERROR,
"Invalid command verb, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR, "Invalid command verb, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
/* Check if mandatory fields are missing */
if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
LOGP(DLMGCP, LOGL_ERROR,
"One or more missing mandatory fields, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR,
"One or more missing mandatory fields, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
@@ -1266,39 +1393,37 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
/* Add endpoint name */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
if (strlen(mgcp_msg->endpoint) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty endpoint name, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR, "Empty endpoint name, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
if (strstr(mgcp_msg->endpoint, "@") == NULL) {
LOGP(DLMGCP, LOGL_ERROR,
"Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
mgcp_msg->endpoint);
LOGPMGW(mgcp, LOGL_ERROR,
"Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
mgcp_msg->endpoint);
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
rc |= msgb_printf(msg, " %s", mgcp_msg->endpoint);
}
/* Add protocol version */
rc += msgb_printf(msg, " MGCP 1.0\r\n");
rc |= msgb_printf(msg, " MGCP 1.0\r\n");
/* Add call id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
rc += msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
rc |= msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
/* Add connection id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
if (strlen(mgcp_msg->conn_id) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty connection id, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR, "Empty connection id, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
rc |= msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
}
/* Using SDP makes sense when a valid IP/Port combination is specifiec,
@@ -1310,33 +1435,34 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
/* Add local connection options (LCO) */
if (!use_sdp
&& (mgcp_msg->verb == MGCP_VERB_CRCX
|| mgcp_msg->verb == MGCP_VERB_MDCX))
rc += add_lco(msg, mgcp_msg);
|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
if (add_lco(msg, mgcp_msg) < 0)
return NULL;
}
/* Add mode */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
rc +=
rc |=
msgb_printf(msg, "M: %s\r\n",
mgcp_client_cmode_name(mgcp_msg->conn_mode));
/* Add X-Osmo-IGN */
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_IGN)
&& (mgcp_msg->x_osmo_ign != 0))
rc +=
rc |=
msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
/* Add X-Osmo-Osmux */
if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID)) {
if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
LOGP(DLMGCP, LOGL_ERROR,
"Wrong Osmux CID %d, can not generate MGCP message\n",
mgcp_msg->x_osmo_osmux_cid);
LOGPMGW(mgcp, LOGL_ERROR, "Wrong Osmux CID %d, can not generate MGCP message\n",
mgcp_msg->x_osmo_osmux_cid);
msgb_free(msg);
return NULL;
}
snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
rc +=
rc |=
msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
}
@@ -1346,16 +1472,12 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
if (use_sdp
&& (mgcp_msg->verb == MGCP_VERB_CRCX
|| mgcp_msg->verb == MGCP_VERB_MDCX)) {
rc_sdp = add_sdp(msg, mgcp_msg, mgcp);
if (rc_sdp == -2)
if (add_sdp(msg, mgcp_msg, mgcp) < 0)
return NULL;
else
rc += rc_sdp;
}
if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"message buffer to small, can not generate MGCP message\n");
LOGPMGW(mgcp, LOGL_ERROR, "Message buffer to small, can not generate MGCP message\n");
msgb_free(msg);
msg = NULL;
}
@@ -1371,7 +1493,7 @@ mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg)
return (mgcp_trans_id_t)msg->cb[MSGB_CB_MGCP_TRANS_ID];
}
/*! Get the configuration parameters a given MGCP client instance
/*! Get the configuration parameters for a given MGCP client instance
* \param[in] mgcp MGCP client descriptor.
* \returns configuration */
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
@@ -1387,3 +1509,22 @@ const struct value_string mgcp_client_connection_mode_strs[] = {
{ MGCP_CONN_LOOPBACK, "loopback" },
{ 0, NULL }
};
/*! Get MGCP client instance name (VTY).
* \param[in] mgcp MGCP client descriptor.
* \returns MGCP client name.
*
* The user can only modify the name of an MGCP client instance when it is
* part of a pool. For single MGCP client instances and MGCP client instance
* where no description is set via the VTY, the MGW domain name will be used
* as name. */
const char *mgcp_client_name(const struct mgcp_client *mgcp)
{
if (!mgcp)
return "(null)";
if (mgcp->actual.description)
return mgcp->actual.description;
else
return mgcp_client_endpoint_domain(mgcp);
}

View File

@@ -27,12 +27,13 @@
#include <osmocom/core/fsm.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
#define LOG_CI(ci, level, fmt, args...) do { \
if (!ci || !ci->ep) \
LOGP(DLGLOBAL, level, "(unknown MGW endpoint) " fmt, ## args); \
LOGP(DLMGCP, level, "(unknown MGW endpoint) " fmt, ## args); \
else \
LOG_MGCPC_EP(ci->ep, level, "CI[%d] %s%s%s: " fmt, \
(int)(ci - ci->ep->ci), \
@@ -215,6 +216,13 @@ const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci)
return ci->mgcp_ci_str;
}
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep)
{
if (!ep)
return NULL;
return ep->mgcp_client;
}
static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
@@ -235,8 +243,6 @@ static void fill_event_names()
}
}
/* T_defs is used to obtain an (Osmocom specific) T2427001: timeout for an MGCP response (note, 2427 corresponds to the
* default MGCP port in osmo-mgw). */
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
{
OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
@@ -468,14 +474,12 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
ci->pending = false;
rtp_info = data;
switch (ci->verb) {
case MGCP_VERB_CRCX:
/* If we sent a wildcarded endpoint name on CRCX, we need to store the resulting endpoint
* name here. Also, we receive the MGW's RTP port information. */
rtp_info = data;
OSMO_ASSERT(rtp_info);
ci->got_port_info = true;
ci->rtp_info = *rtp_info;
osmo_strlcpy(ci->mgcp_ci_str, mgcp_conn_get_ci(ci->mgcp_client_fi),
sizeof(ci->mgcp_ci_str));
if (rtp_info->endpoint[0]) {
@@ -485,6 +489,15 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
return;
}
ci->ep->first_crcx_complete = true;
OSMO_ASSERT(rtp_info);
/* fall through */
case MGCP_VERB_MDCX:
/* Always update the received RTP ip/port information, since MGW
* may provide new one after remote end params changed */
if (rtp_info) {
ci->got_port_info = true;
ci->rtp_info = *rtp_info;
}
break;
default:
@@ -502,7 +515,8 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
}
/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
/*! Return the MGW's local RTP port information for this connection, i.e. the local port that MGW is receiving on, as
* returned by the last CRCX-OK / MDCX-OK message. */
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
{
ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
@@ -513,21 +527,47 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
return &ci->rtp_info;
}
/*! Return the MGW's remote RTP port information for this connection, i.e. the remote RTP port that the MGW is sending
* to, as sent to the MGW by the last CRCX / MDCX message. */
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_remote_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
{
ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
if (!ci)
return NULL;
return &ci->verb_info;
}
/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
{
const struct mgcp_conn_peer *rtp_info;
int family;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
if (!rtp_info)
return false;
sin = (struct sockaddr_in *)dest;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr(rtp_info->addr);
sin->sin_port = osmo_ntohs(rtp_info->port);
family = osmo_ip_str_type(rtp_info->addr);
switch (family) {
case AF_INET:
sin = (struct sockaddr_in *)dest;
sin->sin_family = AF_INET;
sin->sin_port = osmo_ntohs(rtp_info->port);
if (inet_pton(AF_INET, rtp_info->addr, &sin->sin_addr) != 1)
return false;
break;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)dest;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = osmo_ntohs(rtp_info->port);
if (inet_pton(AF_INET6, rtp_info->addr, &sin6->sin6_addr) != 1)
return false;
break;
default:
return false;
}
return true;
}
@@ -547,7 +587,7 @@ bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *
}
static const struct osmo_tdef_state_timeout osmo_mgcpc_ep_fsm_timeouts[32] = {
[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=2427001 },
[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=-2427 },
};
/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.
@@ -583,7 +623,7 @@ void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
ci = osmo_mgcpc_ep_check_ci(ci);
if (!ci) {
LOGP(DLGLOBAL, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");
LOGP(DLMGCP, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");
goto dispatch_error;
}
if (!verb_info && verb != MGCP_VERB_DLCX) {
@@ -957,6 +997,34 @@ 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)
{
int i;
struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
/* We want the mgcp_client_fsm to still stick around until it received the DLCX "OK" responses from the MGW. So
* it should not dealloc along with this ep_fsm instance. Instead, signal DLCX for each conn on the endpoint,
* and detach the mgcp_client_fsm from being a child-fsm.
*
* After mgcp_conn_delete(), an mgcp_client_fsm instance goes into ST_DLCX_RESP, which waits up to 4 seconds for
* a DLCX OK. If none is received in that time, the instance terminates. So cleanup of the instance is
* guaranteed. */
for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];
if (!ci->occupied || !ci->mgcp_client_fi)
continue;
/* mgcp_conn_delete() unlinks itself from this parent FSM implicitly and waits for the DLCX OK. */
mgcp_conn_delete(ci->mgcp_client_fi);
/* Forget all about this ci */
*ci = (struct osmo_mgcpc_ep_ci){
.ep = ep,
};
}
}
static struct osmo_fsm osmo_mgcpc_ep_fsm = {
.name = "mgw-endp",
.states = osmo_mgcpc_ep_fsm_states,
@@ -964,5 +1032,5 @@ static struct osmo_fsm osmo_mgcpc_ep_fsm = {
.log_subsys = DLMGCP,
.event_names = osmo_mgcpc_ep_fsm_event_names,
.timer_cb = osmo_mgcpc_ep_fsm_timer_cb,
/* The FSM termination will automatically trigger any mgcp_client_fsm instances to DLCX. */
.pre_term = osmo_mgcpc_ep_fsm_pre_term,
};

View File

@@ -25,6 +25,7 @@
#include <osmocom/core/byteswap.h>
#include <arpa/inet.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/sockaddr_str.h>
/* Context information, this is attached to the priv pointer of the FSM and
* is also handed back when dispatcheing events to the parent FSM. This is
@@ -251,6 +252,18 @@ const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
return mgcp_ctx->conn_id;
}
/* Get the mgcp_client that is used with this mgcp_client_fsm instance */
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi)
{
struct mgcp_ctx *mgcp_ctx;
if (!fi)
return NULL;
mgcp_ctx = fi->priv;
return mgcp_ctx->mgcp;
}
static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
{
struct osmo_fsm_inst *fi = priv;
@@ -520,10 +533,12 @@ static void fsm_cleanup_cb(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause ca
/* Should the FSM be terminated while there are still open connections
* on the MGW, we send an unconditional DLCX to terminate the
* connection. This is not the normal case. The user should always use
* mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
if (strlen(mgcp_ctx->conn_id)) {
LOGPFSML(fi, LOGL_ERROR,
"MGW/DLCX: abrupt FSM termination with connections still present, sending unconditional DLCX...\n");
* mgcp_conn_delete() to instruct the FSM to perform a graceful exit.
* If in ST_DLCX_RESP, a DLCX was already sent and we did not get a
* response. No point in sending another one. */
if (fi->state != ST_DLCX_RESP && strlen(mgcp_ctx->conn_id)) {
LOGPFSML(fi, LOGL_INFO, "Conn cleanup, sending DLCX for %s %s\n", mgcp_ctx->conn_peer_remote.endpoint,
mgcp_ctx->conn_id);
msg = make_dlcx_msg(mgcp_ctx);
if (!msg)
LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
@@ -593,6 +608,7 @@ static struct osmo_fsm fsm_mgcp_client = {
.timer_cb = fsm_timeout_cb,
.cleanup = fsm_cleanup_cb,
.event_names = fsm_mgcp_client_evt_names,
.log_subsys = DLMGCP,
};
/*! allocate FSM, and create a new connection on the MGW.
@@ -607,14 +623,16 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
{
struct mgcp_ctx *mgcp_ctx;
struct osmo_fsm_inst *fi;
struct in_addr ip_test;
struct in6_addr ip_test;
OSMO_ASSERT(parent_fi);
OSMO_ASSERT(mgcp);
OSMO_ASSERT(conn_peer);
/* Check if IP/Port information in conn info makes sense */
if (conn_peer->port && inet_aton(conn_peer->addr, &ip_test) == 0)
if (conn_peer->port && inet_pton(osmo_ip_str_type(conn_peer->addr),
conn_peer->addr, &ip_test) != 1)
return NULL;
/* Allocate and configure a new fsm instance */
@@ -644,7 +662,7 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
{
OSMO_ASSERT(fi);
struct mgcp_ctx *mgcp_ctx = fi->priv;
struct in_addr ip_test;
struct in6_addr ip_test;
OSMO_ASSERT(mgcp_ctx);
OSMO_ASSERT(conn_peer);
@@ -668,8 +686,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, port == 0\n");
return -EINVAL;
}
if (inet_aton(conn_peer->addr, &ip_test) == 0) {
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address == 0.0.0.0\n");
if (inet_pton(osmo_ip_str_type(conn_peer->addr), conn_peer->addr, &ip_test) != 1) {
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address %s\n", conn_peer->addr);
return -EINVAL;
}
@@ -704,8 +722,8 @@ void mgcp_conn_delete(struct osmo_fsm_inst *fi)
if (fi->proc.terminating)
return;
/* Unlink FSM from parent */
osmo_fsm_inst_unlink_parent(fi, NULL);
/* Unlink FSM from parent, set the struct mgcp_client as new talloc ctx. */
osmo_fsm_inst_unlink_parent(fi, mgcp_ctx->mgcp);
/* An error situation where the parent FSM must be killed immediately
* may lead into a situation where the DLCX can not be executed right

View File

@@ -0,0 +1,216 @@
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool.h>
#include <stddef.h>
#define LOGPPMGW(pool_member, level, fmt, args...) \
LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
/* Get a human readable name for a given pool member. */
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
{
const struct mgcp_client *mpcp_client;
struct mgcp_client mpcp_client_dummy;
static char name[512];
const char *description;
if (!pool_member)
return "(null)";
/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
* initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
if (!pool_member->client) {
memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
mpcp_client = &mpcp_client_dummy;
} else {
mpcp_client = pool_member->client;
}
description = mgcp_client_name(mpcp_client);
snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
return name;
}
/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
* mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
* \param[in] talloc_ctx talloc context. */
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
{
struct mgcp_client_pool *pool;
pool = talloc_zero(talloc_ctx, struct mgcp_client_pool);
if (!pool)
return NULL;
INIT_LLIST_HEAD(&pool->pool);
return pool;
}
/*! Initialize and connect an mcgp client pool.
* \param[in,out] mgcp MGCP client pool descriptor.
* \returns number of successfully initialized pool members. */
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
{
struct mgcp_client_pool_member *pool_member;
unsigned int pool_members_initialized = 0;
llist_for_each_entry(pool_member, &pool->pool, list) {
/* Initialize client */
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
if (!pool_member->client) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
continue;
}
/* Set backpointer so that we can detect later that this MGCP client is managed
* by this pool. */
pool_member->client->pool = pool;
/* Connect client */
if (mgcp_client_connect2(pool_member->client, 0)) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
pool_member->conf.remote_addr, pool_member->conf.remote_port);
talloc_free(pool_member->client);
pool_member->client = NULL;
continue;
}
pool_members_initialized++;
}
return pool_members_initialized;
}
/*! register a single mgcp_client instance to the pool.
* \param[out] pool MGCP client pool descriptor.
* \param[in] mgcp MGCP client descriptor. */
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client)
{
/*! Some applications still support the non-pooled MGW VTY configuration variant provided by
* mgcp_client_vty_init(). If this is the case the mgcp_client instance created by mgcp_client_init()
* can be registered here so that it will appear as if it were part of the pool. When the user actively
* configures MGW pool members, the MGCP client registered here will be ignored. (The registration of
* multiple singe mgcp_client instances is not possible.) */
pool->mgcp_client_single = mgcp_client;
}
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
* pool member that is suitable (has a client, is not blocked, has a low load). */
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
{
struct mgcp_client_pool_member *pool_member;
struct mgcp_client_pool_member *pool_member_picked = NULL;
unsigned int n_pool_members = llist_count(&pool->pool);
llist_for_each_entry(pool_member, &pool->pool, list) {
if (pool_member->blocked == false && pool_member->client) {
if (!pool_member_picked)
pool_member_picked = pool_member;
else if (pool_member_picked->refcount > pool_member->refcount)
pool_member_picked = pool_member;
} else {
LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
pool_member->nr);
}
}
if (pool_member_picked) {
LOGPPMGW(pool_member_picked, LOGL_DEBUG, "MGW pool has %u members -- using MGW %u (active calls: %u)\n",
n_pool_members, pool_member_picked->nr, pool_member_picked->refcount);
return pool_member_picked;
}
LOGP(DLMGCP, LOGL_ERROR,
"MGW pool has %u members, but no functional MGW pool member found -- check configuration!\n",
n_pool_members);
return NULL;
}
/*! get an MGCP client from the pool (increment reference counter).
* \param[in,out] pool MGCP client pool descriptor.
* \returns MGCP client descriptor, NULL if no member was found (empty pool). */
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
{
struct mgcp_client_pool_member *pool_member;
/*! When an MGCP client is taken from the pool it is still available for other calls. In fact only a reference
* counter is incremented to keep track on how many references to a specific MGCP client are currently used
* by the application code. */
/* When the pool is empty, return a single MGCP client if it is registered. */
if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
mgcp_client_name(pool->mgcp_client_single));
return pool->mgcp_client_single;
}
/* Abort when the pool is empty */
if (llist_empty(&pool->pool)) {
LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
return NULL;
}
/* Pick a suitable pool member */
pool_member = mgcp_client_pool_pick(pool);
if (pool_member) {
pool_member->refcount++;
return pool_member->client;
}
return NULL;
}
/*! put an MGCP client back into the pool (decrement reference counter).
* \param[in,out] pool MGCP client pool descriptor.
* \param[in] mgcp MGCP client descriptor.
*
* This function is able to detect automatically to which pool the mgcp_client belongs. If the mgcp_client does
* not belong to a pool at all, the function call will have no effect. */
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
{
struct mgcp_client_pool_member *pool_member;
struct mgcp_client_pool *pool;
if (!mgcp_client)
return;
if (mgcp_client->pool)
pool = mgcp_client->pool;
else
return;
llist_for_each_entry(pool_member, &pool->pool, list) {
if (pool_member->client == mgcp_client) {
if (pool_member->refcount == 0) {
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
return;
}
pool_member->refcount--;
}
}
}

View File

@@ -24,27 +24,47 @@
#include <stdlib.h>
#include <talloc.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/misc.h>
#include <osmocom/core/utils.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
#define MGW_STR MGCP_CLIENT_MGW_STR
void *global_mgcp_client_ctx = NULL;
struct mgcp_client_conf *global_mgcp_client_conf = NULL;
/* Only common (non-pooled) VTY connands 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;
/* MGCP Client configuration used with mgcp_client_vty_init(). (This pointer
* points to user provided memory, so it cannot be used as talloc context.) */
static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
{
if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
return vty->index;
else
return global_mgcp_client_conf;
}
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
"mgw local-ip A.B.C.D",
"mgw local-ip " VTY_IPV46_CMD,
MGW_STR "local bind to connect to MGW from\n"
"local bind IP address\n")
"local bind IPv4 address\n"
"local bind IPv6 address\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcp_client_ctx);
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
osmo_talloc_replace_string(global_mgcp_client_ctx,
(char**)&global_mgcp_client_conf->local_addr,
(char **)&conf->local_addr,
argv[0]);
return CMD_SUCCESS;
}
@@ -58,9 +78,9 @@ DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
MGW_STR "local port to connect to MGW from\n"
"local bind port\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
global_mgcp_client_conf->local_port = atoi(argv[0]);
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
conf->local_port = atoi(argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
@@ -69,16 +89,15 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
"local bind port\n")
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
"mgw remote-ip A.B.C.D",
"mgw remote-ip " VTY_IPV46_CMD,
MGW_STR "remote IP address to reach the MGW at\n"
"remote IP address\n")
"remote IPv4 address\n"
"remote IPv6 address\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcp_client_ctx);
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
osmo_talloc_replace_string(global_mgcp_client_ctx,
(char**)&global_mgcp_client_conf->remote_addr,
argv[0]);
(char **)&conf->remote_addr, argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
@@ -91,9 +110,9 @@ DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
MGW_STR "remote port to reach the MGW at\n"
"remote port\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
global_mgcp_client_conf->remote_port = atoi(argv[0]);
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
conf->remote_port = atoi(argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
@@ -143,66 +162,396 @@ DEFUN(cfg_mgw_endpoint_domain_name,
MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
"Domain name, should be alphanumeric.\n")
{
if (osmo_strlcpy(global_mgcp_client_conf->endpoint_domain_name, argv[0],
sizeof(global_mgcp_client_conf->endpoint_domain_name))
>= sizeof(global_mgcp_client_conf->endpoint_domain_name)) {
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
if (osmo_strlcpy(conf->endpoint_domain_name, argv[0], sizeof(conf->endpoint_domain_name))
>= sizeof(conf->endpoint_domain_name)) {
vty_out(vty, "%% Error: 'mgw endpoint-domain' name too long, max length is %zu: '%s'%s",
sizeof(global_mgcp_client_conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);
sizeof(conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
int mgcp_client_config_write(struct vty *vty, const char *indent)
DEFUN(cfg_mgw_reset_ep_name,
cfg_mgw_reset_ep_name_cmd,
"mgw reset-endpoint NAME",
MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
"e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
{
const char *addr;
int port;
int rc;
struct reset_ep *reset_ep;
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
addr = global_mgcp_client_conf->local_addr;
if (addr)
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
VTY_NEWLINE);
port = global_mgcp_client_conf->local_port;
if (port >= 0)
vty_out(vty, "%smgw local-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
/* stop when the address is already in the list */
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
if (strcmp(argv[0], reset_ep->name) == 0) {
vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
}
addr = global_mgcp_client_conf->remote_addr;
if (addr)
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
VTY_NEWLINE);
port = global_mgcp_client_conf->remote_port;
if (port >= 0)
vty_out(vty, "%smgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
/* the domain name is not part of the actual endpoint name */
if (strchr(argv[0], '@')) {
vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
if (global_mgcp_client_conf->endpoint_domain_name[0])
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);
reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);
OSMO_ASSERT(reset_ep);
rc = osmo_strlcpy(reset_ep->name, argv[0], sizeof(reset_ep->name));
if (rc >= sizeof(reset_ep->name)) {
vty_out(vty, "%% Error: 'mgw reset-endpoint' name too long, max length is %zu: '%s'%s",
sizeof(reset_ep->name) - 1, argv[0], VTY_NEWLINE);
talloc_free(reset_ep);
return CMD_WARNING;
}
llist_add_tail(&reset_ep->list, &conf->reset_epnames);
return CMD_SUCCESS;
}
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
DEFUN(cfg_mgw_no_reset_ep_name,
cfg_mgw_no_reset_ep_name_cmd,
"no mgw reset-endpoint NAME",
NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
"Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
{
struct reset_ep *reset_ep;
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
if (strcmp(argv[0], reset_ep->name) == 0) {
llist_del(&reset_ep->list);
talloc_free(reset_ep);
return CMD_SUCCESS;
}
}
vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
{
const char *addr;
int port;
struct reset_ep *reset_ep;
if (conf->description)
vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
addr = conf->local_addr;
if (addr)
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
VTY_NEWLINE);
port = conf->local_port;
if (port >= 0)
vty_out(vty, "%smgw local-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
addr = conf->remote_addr;
if (addr)
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
VTY_NEWLINE);
port = conf->remote_port;
if (port >= 0)
vty_out(vty, "%smgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
if (conf->endpoint_domain_name[0])
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
conf->endpoint_domain_name, VTY_NEWLINE);
llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
return CMD_SUCCESS;
}
/*! Write out MGCP client config to VTY.
* \param[in] vty VTY to which we should print.
* \param[in] string used for indentation (e.g. " ").
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
int mgcp_client_config_write(struct vty *vty, const char *indent)
{
return config_write(vty, indent, global_mgcp_client_conf);
}
static void vty_init_common(void *talloc_ctx, int node)
{
global_mgcp_client_ctx = talloc_ctx;
global_mgcp_client_conf = conf;
install_element(node, &cfg_mgw_local_ip_cmd);
install_element(node, &cfg_mgw_local_port_cmd);
install_element(node, &cfg_mgw_remote_ip_cmd);
install_element(node, &cfg_mgw_remote_port_cmd);
install_element(node, &cfg_mgw_endpoint_range_cmd);
install_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
install_element(node, &cfg_mgw_endpoint_domain_name_cmd);
/* deprecated 'mgcpgw' commands */
install_element(node, &cfg_mgcpgw_local_ip_cmd);
install_element(node, &cfg_mgcpgw_local_port_cmd);
install_element(node, &cfg_mgcpgw_remote_ip_cmd);
install_element(node, &cfg_mgcpgw_remote_port_cmd);
install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
install_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
install_lib_element(node, &cfg_mgw_local_ip_cmd);
install_lib_element(node, &cfg_mgw_local_port_cmd);
install_lib_element(node, &cfg_mgw_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);
osmo_fsm_vty_add_cmds();
}
/*! Set up MGCP client VTY
* (called once at startup by the application process).
* \param[in] talloc_ctx talloc context to be used by the VTY for allocating memory.
* \param[in] node identifier of the node on which the VTY commands should be installed.
* \param[in] conf user provided memory to to store the MGCP client configuration data. */
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
{
global_mgcp_client_conf = conf;
/* deprecated 'mgcpgw' commands */
install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
install_lib_element(node, &cfg_mgcpgw_local_port_cmd);
install_lib_element(node, &cfg_mgcpgw_remote_ip_cmd);
install_lib_element(node, &cfg_mgcpgw_remote_port_cmd);
install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);
install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
vty_init_common(talloc_ctx, node);
}
static int config_write_pool(struct vty *vty)
{
struct mgcp_client_pool *pool = global_mgcp_client_pool;
struct mgcp_client_pool_member *pool_member;
unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
char *indent = talloc_zero_size(vty, indent_buf_len);
snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
llist_for_each_entry(pool_member, &pool->pool, list) {
vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
config_write(vty, indent, &pool_member->conf);
}
talloc_free(indent);
return CMD_SUCCESS;
}
/* Lookup the selected MGCP client config by its reference number */
static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
{
struct mgcp_client_pool_member *pool_member = NULL;
struct mgcp_client_pool_member *pool_member_tmp;
llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
if (pool_member_tmp->nr == nr) {
pool_member = pool_member_tmp;
break;
}
}
return pool_member;
}
DEFUN_ATTR(cfg_mgw,
cfg_mgw_cmd, "mgw <0-255>", "Select a MGCP client config to setup\n" "reference number\n", CMD_ATTR_IMMEDIATE)
{
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member;
pool_member = pool_member_by_nr(nr);
if (!pool_member) {
pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
OSMO_ASSERT(pool_member);
mgcp_client_conf_init(&pool_member->conf);
pool_member->nr = nr;
llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
}
vty->index = &pool_member->conf;
vty->index_sub = &pool_member->conf.description;
vty->node = global_mgcp_client_pool->vty_node->node;
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_no_mgw,
cfg_no_mgw_cmd,
"no mgw <0-255>", NO_STR "Select a MGCP client config to remove\n" "reference number\n", CMD_ATTR_IMMEDIATE)
{
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member;
pool_member = pool_member_by_nr(nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
/* Make sure that there are no ongoing calls */
if (pool_member->refcount > 0) {
vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't remove it now!%s",
mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
return CMD_WARNING;
}
llist_del(&pool_member->list);
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
talloc_free(pool_member);
return CMD_SUCCESS;
}
DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
"mgw <0-255> reconnect",
MGW_STR "reference number\n" "reconfigure and reconnect MGCP client\n", CMD_ATTR_IMMEDIATE)
{
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
/* Make sure that there are no ongoing calls */
if (pool_member->refcount > 0) {
vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't reconnect it now!%s",
mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
return CMD_WARNING;
}
/* Get rid of a possibly existing old MGCP client instance first */
if (pool_member->client) {
mgcp_client_disconnect(pool_member->client);
talloc_free(pool_member->client);
}
/* Create a new MGCP client instance with the current config */
pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
if (!pool_member->client) {
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
mgcp_client_pool_member_name(pool_member));
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
pool_member->client->pool = global_mgcp_client_pool;
/* Connect client */
if (mgcp_client_connect(pool_member->client)) {
LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
pool_member->conf.remote_port);
talloc_free(pool_member->client);
pool_member->client = NULL;
vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN_ATTR(mgw_block, mgw_block_cmd,
"mgw <0-255> block",
MGW_STR "reference number\n" "block MGCP client so that it won't be used for new calls\n", CMD_ATTR_IMMEDIATE)
{
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
pool_member->blocked = true;
return CMD_SUCCESS;
}
DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
"mgw <0-255> unblock",
MGW_STR "reference number\n" "unblock MGCP client so that it will be available for new calls\n", CMD_ATTR_IMMEDIATE)
{
int nr = atoi(argv[0]);
struct mgcp_client_pool_member *pool_member = NULL;
pool_member = pool_member_by_nr(nr);
if (!pool_member) {
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
pool_member->blocked = false;
return CMD_SUCCESS;
}
DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
{
vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
struct mgcp_client_pool_member *pool_member;
if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
vty_out(vty, "%% (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
return CMD_SUCCESS;
} else if (llist_empty(&global_mgcp_client_pool->pool)) {
vty_out(vty, "%% (pool is empty)%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
vty_out(vty, "%% MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
vty_out(vty, "%% mgcp-client: %s%s", pool_member->client ? "connected" : "disconnected",
VTY_NEWLINE);
vty_out(vty, "%% service: %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
vty_out(vty, "%% ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
/*! Set up MGCP client VTY (pooled)
* (called once at startup by the application process).
* \param[in] parent_node identifier of the parent node on which the mgw node appears.
* \param[in] mgw_node identifier that should be used with the newly installed MGW node.
* \param[in] indent indentation string to match the indentation in the VTY config
* \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
{
/* A pool must be allocated before this function can be called */
OSMO_ASSERT(pool);
/* Never allow this function to be called twice on the same pool */
OSMO_ASSERT(!pool->vty_indent);
OSMO_ASSERT(!pool->vty_node);
pool->vty_indent = talloc_strdup(pool, indent);
OSMO_ASSERT(pool->vty_indent);
pool->vty_node = talloc_zero(pool, struct cmd_node);
OSMO_ASSERT(pool->vty_node);
pool->vty_node->node = mgw_node;
pool->vty_node->vtysh = 1;
pool->vty_node->prompt = talloc_strdup(pool->vty_node, "%s(config-mgw)# ");
install_lib_element(parent_node, &cfg_mgw_cmd);
install_lib_element(parent_node, &cfg_no_mgw_cmd);
install_node(pool->vty_node, config_write_pool);
vty_init_common(pool, mgw_node);
install_element(mgw_node, &cfg_description_cmd);
install_lib_element(ENABLE_NODE, &mgw_reconnect_cmd);
install_lib_element(ENABLE_NODE, &mgw_block_cmd);
install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
install_lib_element_ve(&mgw_snow_cmd);
global_mgcp_client_pool = pool;
}

View File

@@ -89,15 +89,13 @@ static void codec_init(struct mgcp_rtp_codec *codec)
.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN,
.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE,
.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS,
.subtype_name = "",
.audio_name = "",
};
}
static void codec_free(struct mgcp_rtp_codec *codec)
{
if (codec->subtype_name)
talloc_free(codec->subtype_name);
if (codec->audio_name)
talloc_free(codec->audio_name);
*codec = (struct mgcp_rtp_codec){};
}
@@ -124,10 +122,8 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
{
int rate;
int channels;
char audio_codec[64];
struct mgcp_rtp_codec *codec;
unsigned int pt_offset = conn->end.codecs_assigned;
void *ctx = conn->conn;
/* The amount of codecs we can store is limited, make sure we do not
* overrun this limit. */
@@ -160,16 +156,16 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
if (!audio_name) {
switch (payload_type) {
case 0:
audio_name = talloc_strdup(ctx, "PCMU/8000/1");
strcpy(codec->audio_name, "PCMU/8000/1");
break;
case 3:
audio_name = talloc_strdup(ctx, "GSM/8000/1");
strcpy(codec->audio_name, "GSM/8000/1");
break;
case 8:
audio_name = talloc_strdup(ctx, "PCMA/8000/1");
strcpy(codec->audio_name, "PCMA/8000/1");
break;
case 18:
audio_name = talloc_strdup(ctx, "G729/8000/1");
strcpy(codec->audio_name, "G729/8000/1");
break;
default:
/* The given payload type is not known to us, or it
@@ -179,36 +175,36 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
payload_type);
goto error;
}
} else {
OSMO_STRLCPY_ARRAY(codec->audio_name, audio_name);
}
/* Now we extract the codec subtype name, rate and channels. The latter
* two are optional. If they are not present we use the safe defaults
* above. */
if (strlen(audio_name) >= sizeof(audio_codec)) {
LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(audio_name, -1));
if (strlen(codec->audio_name) >= sizeof(codec->subtype_name)) {
LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(codec->audio_name, -1));
goto error;
}
channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1) {
LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(audio_name, -1));
if (sscanf(codec->audio_name, "%63[^/]/%d/%d", codec->subtype_name, &rate, &channels) < 1) {
LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(codec->audio_name, -1));
goto error;
}
/* Note: We only accept configurations with one audio channel! */
if (channels != 1) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot handle audio codec with more than one channel: %s\n",
osmo_quote_str(audio_name, -1));
osmo_quote_str(codec->audio_name, -1));
goto error;
}
codec->rate = rate;
codec->channels = channels;
codec->subtype_name = talloc_strdup(ctx, audio_codec);
codec->audio_name = talloc_strdup(ctx, audio_name);
codec->payload_type = payload_type;
if (!strcmp(audio_codec, "G729")) {
if (!strcmp(codec->subtype_name, "G729")) {
codec->frame_duration_num = 10;
codec->frame_duration_den = 1000;
} else {
@@ -287,7 +283,7 @@ static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct m
/* A codec name must be set, if not, this might mean that the codec
* (payload type) that was assigned is unknown to us so we must stop
* here. */
if (!codec->subtype_name)
if (!strlen(codec->subtype_name))
return false;
/* FIXME: implement meaningful checks to make sure that the given codec

View File

@@ -21,6 +21,7 @@
*
*/
#include <stdatomic.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_network.h>
#include <osmocom/mgcp/mgcp_protocol.h>
@@ -89,7 +90,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
/* FIXME: Each new rate counter group requires an unique index. At the
* moment we generate this index using this counter, but perhaps there
* is a more concious way to assign the indexes. */
static unsigned int rate_ctr_index = 0;
static atomic_uint rate_ctr_index = 0;
conn_rtp->type = MGCP_RTP_DEFAULT;
conn_rtp->osmux.cid_allocated = false;
@@ -110,13 +111,12 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
end->output_enabled = 0;
end->maximum_packet_time = -1;
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
if (!conn_rtp->rate_ctr_group)
return -1;
conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];
conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];
rate_ctr_index++;
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);
/* Make sure codec table is reset */
mgcp_codec_reset_all(conn_rtp);
@@ -143,7 +143,7 @@ void mgcp_conn_watchdog_cb(void *data)
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
{
int timeout = conn->endp->cfg->conn_timeout;
int timeout = conn->endp->trunk->cfg->conn_timeout;
if (!timeout)
return;
@@ -199,7 +199,7 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
/* Initialize watchdog */
osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
mgcp_conn_watchdog_kick(conn);
llist_add(&conn->entry, &endp->conns);
mgcp_endp_add_conn(endp, conn);
return conn;
}
@@ -270,12 +270,12 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
/* all other counters are [now] updated in real-time */
rate_ctr_add(&all_stats->ctr[IN_STREAM_ERR_TSTMP_CTR],
conn_stats->ctr[IN_STREAM_ERR_TSTMP_CTR].current);
rate_ctr_add(&all_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR],
conn_stats->ctr[OUT_STREAM_ERR_TSTMP_CTR].current);
rate_ctr_add(rate_ctr_group_get_ctr(all_stats, IN_STREAM_ERR_TSTMP_CTR),
rate_ctr_group_get_ctr(conn_stats, IN_STREAM_ERR_TSTMP_CTR)->current);
rate_ctr_add(rate_ctr_group_get_ctr(all_stats, OUT_STREAM_ERR_TSTMP_CTR),
rate_ctr_group_get_ctr(conn_stats, OUT_STREAM_ERR_TSTMP_CTR)->current);
rate_ctr_inc(&all_stats->ctr[RTP_NUM_CONNECTIONS]);
rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
}
/*! free a connection by its ID.
@@ -289,12 +289,6 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
if (!conn)
return;
/* Run endpoint cleanup action. By this we inform the endpoint about
* the removal of the connection and allow it to clean up its inner
* state accordingly */
if (endp->type->cleanup_cb)
endp->type->cleanup_cb(endp, conn);
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
aggregate_rtp_conn_stats(endp, &conn->u.rtp);
@@ -308,7 +302,8 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
}
osmo_timer_del(&conn->watchdog);
llist_del(&conn->entry);
mgcp_endp_remove_conn(endp, conn);
/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
talloc_free(conn);
}
@@ -333,12 +328,10 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
struct mgcp_conn *conn_tmp;
/* Drop all items in the list */
llist_for_each_entry_safe(conn, conn_tmp, &endp->conns, entry) {
/* Drop all items in the list, might be consecutive! */
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
mgcp_conn_free(endp, conn->id);
}
return;
}
@@ -349,6 +342,7 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp)
char *mgcp_conn_dump(struct mgcp_conn *conn)
{
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
char ipbuf[INET6_ADDRSTRLEN];
if (!conn) {
snprintf(str, sizeof(str), "(null connection)");
@@ -362,7 +356,7 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
"rtp:%u rtcp:%u)",
conn->name,
conn->id,
inet_ntoa(conn->u.rtp.end.addr),
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));
break;

View File

@@ -192,12 +192,12 @@ static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_dat
{
struct mgcp_endpoint *endp = user_data;
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
struct msgb *msg = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
uint8_t *ptr;
const uint8_t *ptr_ft;
enum osmo_trau_frame_type ft;
rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_MUX_EMPTY_CTR]);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
/* Choose an appropiate idle frame type */
ft = endp->e1.trau_rtp_st->type;
@@ -238,9 +238,9 @@ static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_da
* (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */
static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)
{
struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx-from-E1");
unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
struct mgcp_endpoint *endp = user_data;
struct msgb *msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx-from-E1");
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
struct mgcp_conn *conn_dst;
struct osmo_trau_frame fr;
@@ -304,7 +304,7 @@ static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int
msgb_free(msg);
return;
skip:
rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_RX_FAIL_CTR]);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
msgb_free(msg);
return;
}
@@ -312,7 +312,7 @@ skip:
/* Function to handle outgoing E1 traffic */
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
{
struct msgb *msg = msgb_alloc(E1_TS_BYTES, "E1-TX-timeslot-bytes");
struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
uint8_t *ptr;
/* Get E1 frame from I.460 multiplexer */
@@ -337,7 +337,8 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
/* Find associated trunk */
trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
if (!trunk) {
LOGP(DE1, LOGL_DEBUG, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
LOGP(DE1, LOGL_ERROR, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
msgb_free(msg);
return;
}
@@ -359,13 +360,12 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
/* Trigger sending of pending E1 traffic */
e1_send(ts, trunk);
/* e1inp_rx_ts() does not free() msgb */
msgb_free(msg);
}
/*! Find an endpoint by its name on a specified trunk.
* \param[in] trunk trunk configuration.
* \param[in] ts_nr E1 timeslot number.
* \returns -EINVAL on failure, 0 on success. */
int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
{
/*! Each timeslot needs only to be configured once. The Timeslot then
* stays open and permanently receives data. It is then up to the
@@ -380,33 +380,32 @@ int mgcp_e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
cfg = trunk->cfg;
if (trunk->e1.ts_in_use[ts_nr - 1]) {
LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u already set up, skipping...\n", ts_nr);
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
return 0;
}
/* Get E1 line */
if (!trunk->e1.line) {
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
if (!e1_line) {
LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "no such E1 line %u - check VTY config!\n",
trunk->e1.vty_line_nr);
return -EINVAL;
}
e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops);
} else
e1_line = trunk->e1.line;
if (!e1_line)
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
if (!e1_line) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
trunk->e1.vty_line_nr);
return -EINVAL;
}
e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops);
/* Configure E1 timeslot */
rc = e1inp_ts_config_raw(&e1_line->ts[ts_nr - 1], e1_line, e1_recv_cb);
if (rc < 0)
if (rc < 0) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to put E1 timeslot %u in raw mode.\n", ts_nr);
return -EINVAL;
e1inp_line_update(e1_line);
if (rc < 0)
}
rc = e1inp_line_update(e1_line);
if (rc < 0) {
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
return -EINVAL;
}
LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u set up successfully.\n", ts_nr);
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
trunk->e1.ts_in_use[ts_nr - 1] = true;
return 0;
@@ -518,7 +517,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
endp->e1.last_amr_ft = AMR_4_75;
/* Set up E1 line / timeslot */
rc = mgcp_e1_init(endp->trunk, ts);
rc = e1_init(endp->trunk, ts);
if (rc != 0)
return -EINVAL;
@@ -550,7 +549,7 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8
endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;
endp->e1.scd.mux.user_data = endp;
LOGPENDP(endp, DE1, LOGL_DEBUG, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
LOGPENDP(endp, DE1, LOGL_INFO, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
offs, e1_rates[ss], endp->e1.scd.demux.num_bits);
endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);
if (!endp->e1.schan) {
@@ -627,7 +626,7 @@ void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
* \returns 0 on success, -1 on ERROR. */
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
{
struct msgb *msg_tf = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
struct msgb *msg_tf = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
struct osmo_trau_frame tf;
@@ -684,7 +683,7 @@ int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, s
return 0;
skip:
rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_TX_FAIL_CTR]);
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
msgb_free(msg_tf);
return -1;
}

View File

@@ -27,9 +27,10 @@
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/mgcp/mgcp_e1.h>
#include <osmocom/core/stat_item.h>
#define E1_TIMESLOTS 32
#define E1_RATE_MAX 64
#define E1_OFFS_MAX 8
@@ -58,7 +59,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain,
}
/* Generate E1 endpoint name from given numeric parameters */
static char *gen_e1_epname(void *ctx, const char *domain, uint8_t trunk_nr,
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
uint8_t ts_nr, uint8_t ss_nr)
{
unsigned int rate;
@@ -88,7 +89,6 @@ struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
return NULL;
INIT_LLIST_HEAD(&endp->conns);
endp->cfg = trunk->cfg;
endp->trunk = trunk;
switch (trunk->trunk_type) {
@@ -122,6 +122,12 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
* RSIP is executed), free them all at once. */
mgcp_conn_free_all(endp);
/* We must only decrement the stat item when the endpoint as actually
* claimed. An endpoint is claimed when a call-id is set */
if (endp->callid)
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
TRUNK_STAT_ENDPOINTS_USED), 1);
/* Reset endpoint parameters and states */
talloc_free(endp->callid);
endp->callid = NULL;
@@ -129,7 +135,6 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
endp->local_options.string = NULL;
talloc_free(endp->local_options.codec);
endp->local_options.codec = NULL;
endp->wildcarded_req = false;
if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
mgcp_e1_endp_release(endp);
@@ -182,12 +187,16 @@ static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
}
}
/* Convert all characters in epname to lowercase and strip trunk prefix and
/*! Convert all characters in epname to lowercase and strip trunk prefix and
* endpoint name suffix (domain name) from epname. The result is written to
* to the memory pointed at by epname_stripped. The expected size of the
* result is either equal or lower then the length of the input string
* (epname) */
static void strip_epname(char *epname_stripped, const char *epname,
* (epname)
* \param[out] epname_stripped pointer to store the stripped ep name.
* \param[in] epname endpoint name to lookup.
* \param[in] trunk where the endpoint is located. */
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
const struct mgcp_trunk *trunk)
{
osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
@@ -214,9 +223,11 @@ static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
return NULL;
}
/* Find an endpoint specified by its name. If the endpoint can not be found,
* return NULL */
static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
/*! Find an endpoint of a trunk specified by its name.
* \param[in] epname endpoint name to check.
* \param[in] trunk mgcp_trunk that might have this endpoint.
* \returns NULL if no ep found, else endpoint. */
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
const struct mgcp_trunk *trunk)
{
char epname_stripped[MGCP_ENDPOINT_MAXLEN];
@@ -225,11 +236,11 @@ static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
unsigned int i;
/* Strip irrelevant information from the endpoint name */
strip_epname(epname_stripped, epname, trunk);
mgcp_endp_strip_name(epname_stripped, epname, trunk);
for (i = 0; i < trunk->number_endpoints; i++) {
endp = trunk->endpoints[i];
strip_epname(epname_stripped_endp, endp->name, trunk);
mgcp_endp_strip_name(epname_stripped_endp, endp->name, trunk);
if (strcmp(epname_stripped_endp, epname_stripped) == 0)
return endp;
}
@@ -237,6 +248,18 @@ static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
return NULL;
}
/*! Check if the given epname refers to a wildcarded request or to a specific
* endpoint.
* \param[in] epname endpoint name to check
* \returns true if epname refers to wildcarded request, else false. */
bool mgcp_endp_is_wildcarded(const char *epname)
{
if (strstr(epname, "*"))
return true;
return false;
}
/*! Find an endpoint by its name on a specified trunk.
* \param[out] cause pointer to store cause code, can be NULL.
* \param[in] epname endpoint name to lookup.
@@ -253,13 +276,12 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
/* At the moment we only support a primitive ('*'-only) method of
* wildcarded endpoint searches that picks the next free endpoint on
* a trunk. */
if (strstr(epname, "*")) {
if (mgcp_endp_is_wildcarded(epname)) {
endp = find_free_endpoint(trunk);
if (endp) {
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
"(trunk:%d) found free endpoint: %s\n",
trunk->trunk_nr, endp->name);
endp->wildcarded_req = true;
return endp;
}
@@ -273,12 +295,11 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
/* Find an endpoint by its name (if wildcarded request is not
* applicable) */
endp = find_specific_endpoint(epname, trunk);
endp = mgcp_endp_find_specific(epname, trunk);
if (endp) {
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
"(trunk:%d) found endpoint: %s\n",
trunk->trunk_nr, endp->name);
endp->wildcarded_req = false;
return endp;
}
@@ -291,32 +312,6 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
return NULL;
}
/* Check if the domain name, which is supplied with the endpoint name
* matches the configuration. */
static int check_domain_name(const char *epname, struct mgcp_config *cfg)
{
char *domain_to_check;
domain_to_check = strstr(epname, "@");
if (!domain_to_check) {
LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
epname, cfg->domain);
return -EINVAL;
}
/* Accept any domain if configured as "*" */
if (!strcmp(cfg->domain, "*"))
return 0;
if (strcmp(domain_to_check+1, cfg->domain) != 0) {
LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
epname, cfg->domain);
return -EINVAL;
}
return 0;
}
/*! Find an endpoint by its name, search at all trunks.
* \param[out] cause, pointer to store cause code, can be NULL.
* \param[in] epname, must contain trunk prefix.
@@ -340,10 +335,6 @@ struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
if (!trunk)
return NULL;
/* All endpoint names require a domain as suffix */
if (check_domain_name(epname, cfg))
return NULL;
/* Identify the endpoint on the trunk */
endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
if (!endp) {
@@ -375,7 +366,7 @@ static uint8_t e1_ts_nr_from_epname(const char *epname)
if (strncmp(token, "s-", 2) == 0) {
errno = 0;
res = strtoul(token + 2, NULL, 10);
if (errno == ERANGE || res > E1_TIMESLOTS)
if (errno == ERANGE || res > NUM_E1_TS)
return 0xff;
return (uint8_t) res;
}
@@ -555,7 +546,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp)
epname_check = gen_e1_epname(endp, endp->trunk->cfg->domain,
endp->trunk->trunk_nr, ts_nr,
interlock[i]);
endp_check = find_specific_endpoint(epname_check, endp->trunk);
endp_check = mgcp_endp_find_specific(epname_check, endp->trunk);
if (!endp_check) {
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
"cannot check endpoint availability, overlapping endpoint:%s not found!\n",
@@ -619,6 +610,8 @@ int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
* connection ids) */
endp->callid = talloc_strdup(endp, callid);
OSMO_ASSERT(endp->callid);
osmo_stat_item_inc(osmo_stat_item_group_get_item(endp->trunk->stats.common,
TRUNK_STAT_ENDPOINTS_USED), 1);
/* Allocate resources */
switch (endp->trunk->trunk_type) {
@@ -641,8 +634,7 @@ int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
OSMO_ASSERT(false);
}
/* Make sure the endpoint is released when claiming the endpoint
* failes. */
/* Make sure the endpoint is released when claiming the endpoint fails. */
if (rc < 0)
mgcp_endp_release(endp);
@@ -666,3 +658,20 @@ void mgcp_endp_update(struct mgcp_endpoint *endp)
OSMO_ASSERT(false);
}
}
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
{
llist_add(&conn->entry, &endp->conns);
}
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
{
/* Run endpoint cleanup action. By this we inform the endpoint about
* the removal of the connection and allow it to clean up its inner
* state accordingly */
if (endp->type->cleanup_cb)
endp->type->cleanup_cb(endp, conn);
llist_del(&conn->entry);
if (llist_empty(&endp->conns))
mgcp_endp_release(endp);
}

View File

@@ -31,6 +31,7 @@
#include <osmocom/mgcp/mgcp_msg.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
/*! Display an mgcp message on the log output.
* \param[in] message mgcp message string
@@ -107,7 +108,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
ret = -1;
}
/* Special handling für RTP connections */
/* Special handling for RTP connections */
if (conn->type == MGCP_CONN_TYPE_RTP) {
conn->u.rtp.end.output_enabled =
conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
@@ -132,24 +133,19 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
}
/*! Analyze and parse the the hader of an MGCP messeage string.
* \param[out] pdata caller provided memory to store the parsing results
* \param[in] data mgcp message string
* \returns when the status line was complete and transaction_id and
* endp out parameters are set, -1 on error */
* \param[out] pdata caller provided memory to store the parsing results.
* \param[in] data mgcp message string.
* \returns 0 when the status line was complete and parseable, negative (MGCP
* cause code) on error. */
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
{
int i = 0;
char *elem, *save = NULL;
int cause;
/*! This function will parse the header part of the received
* MGCP message. The parsing results are stored in pdata.
* The function will also automatically search the pool with
* available endpoints in order to find an endpoint that matches
* the endpoint string in in the header */
* MGCP message. The parsing results are stored in pdata. */
OSMO_ASSERT(data);
pdata->trans = "000000";
for (elem = strtok_r(data, " ", &save); elem;
elem = strtok_r(NULL, " ", &save)) {
@@ -158,13 +154,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
pdata->trans = elem;
break;
case 1:
pdata->endp = mgcp_endp_by_name(&cause, elem, pdata->cfg);
if (!pdata->endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Unable to find Endpoint `%s'\n", elem);
OSMO_ASSERT(cause < 0);
return cause;
}
pdata->epname = elem;
break;
case 2:
if (strcasecmp("MGCP", elem)) {
@@ -174,11 +164,8 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
}
break;
case 3:
if (strcmp("1.0", elem)) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
"not supported\n", elem);
if (strcmp("1.0", elem))
return -528;
}
break;
}
i++;
@@ -186,8 +173,6 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
if (i != 4) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
pdata->trans = "000000";
pdata->endp = NULL;
return -510;
}
@@ -224,28 +209,30 @@ int mgcp_parse_osmux_cid(const char *line)
}
/*! Check MGCP parameter line (string) for plausibility.
* \param[in] endp pointer to endpoint (only used for log output)
* \param[in] endp pointer to endpoint (only used for log output, may be NULL)
* \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
* \param[in] line single parameter line from the MGCP message
* \returns 1 when line seems plausible, 0 on error */
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
* \returns true when line seems plausible, false on error */
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
{
const size_t line_len = strlen(line);
if (line[0] != '\0' && line_len < 2) {
LOGP(DLMGCP, LOGL_ERROR,
"Wrong MGCP option format: '%s' on %s\n",
line, endp->name);
return 0;
if (endp)
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
else
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
return false;
}
/* FIXME: A couple more checks wouldn't hurt... */
return 1;
return true;
}
/*! Check if the specified callid seems plausible.
* \param[in] endp pointer to endpoint
* \param{in] callid to verify
* \returns 1 when callid seems plausible, 0 on error */
* \returns 0 when callid seems plausible, -1 on error */
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
{
/*! This function compares the supplied callid with the called that is

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@ static LLIST_HEAD(osmux_handle_list);
struct osmux_handle {
struct llist_head head;
struct mgcp_conn_rtp *conn;
struct osmux_in_handle *in;
struct in_addr rem_addr;
int rem_port; /* network byte order */
@@ -47,14 +48,17 @@ static void *osmux;
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
{
struct osmux_handle *handle = data;
struct sockaddr_in out = {
.sin_family = AF_INET,
.sin_port = handle->rem_port,
};
struct mgcp_conn_rtp *conn = handle->conn;
memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
(struct sockaddr *)&out, sizeof(out));
if (conn->end.output_enabled) {
struct sockaddr_in out = {
.sin_family = AF_INET,
.sin_port = handle->rem_port,
};
memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
(struct sockaddr *)&out, sizeof(out));
}
msgb_free(batch_msg);
}
@@ -109,13 +113,15 @@ static void osmux_handle_put(struct osmux_in_handle *in)
/* Allocate free OSMUX handle */
static struct osmux_handle *
osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_port)
{
struct osmux_handle *h;
struct mgcp_config *cfg = conn->conn->endp->trunk->cfg;
h = talloc_zero(osmux, struct osmux_handle);
if (!h)
return NULL;
h->conn = conn;
h->rem_addr = *addr;
h->rem_port = rem_port;
h->refcnt++;
@@ -148,15 +154,20 @@ osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
/* Lookup existing handle for a specified address, if the handle can not be
* found, the function will automatically allocate one */
static struct osmux_in_handle *
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
osmux_handle_lookup(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *addr, int rem_port)
{
struct osmux_handle *h;
h = osmux_handle_find_get(addr, rem_port);
if (addr->u.sa.sa_family != AF_INET) {
LOGP(DLMGCP, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n");
return NULL;
}
h = osmux_handle_find_get(&addr->u.sin.sin_addr, rem_port);
if (h != NULL)
return h->in;
h = osmux_handle_alloc(cfg, addr, rem_port);
h = osmux_handle_alloc(conn, &addr->u.sin.sin_addr, rem_port);
if (h == NULL)
return NULL;
@@ -236,7 +247,7 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
{
struct mgcp_conn_rtp *conn = data;
struct mgcp_endpoint *endp = conn->conn->endp;
struct sockaddr_in addr = { /* FIXME: do we know the source address?? */ };
struct osmo_sockaddr addr = { /* FIXME: do we know the source address?? */ };
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
*mc = (struct osmo_rtp_msg_ctx){
.proto = MGCP_PROTO_RTP,
@@ -275,6 +286,8 @@ static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
bool sending)
{
char ipbuf[INET6_ADDRSTRLEN];
switch(conn->osmux.state) {
case OSMUX_STATE_ACTIVATING:
if (osmux_enable_conn(endp, conn, &conn->end.addr, conn->end.rtp_port) < 0) {
@@ -287,7 +300,8 @@ static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_r
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"Osmux %s CID %u towards %s:%u is now enabled\n",
sending ? "sent" : "received",
conn->osmux.cid, inet_ntoa(conn->end.addr),
conn->osmux.cid,
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
ntohs(conn->end.rtp_port));
return 0;
case OSMUX_STATE_ENABLED:
@@ -361,7 +375,7 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
}
/* not any further processing dummy messages */
if (msg->data[0] == MGCP_DUMMY_LOAD)
if (mgcp_is_rtp_dummy_payload(msg))
return osmux_handle_dummy(cfg, &addr, msg);
rem = msg->len;
@@ -376,6 +390,8 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
goto out;
}
mgcp_conn_watchdog_kick(conn_src->conn);
/*conn_dst = mgcp_find_dst_conn(conn_src->conn);
if (!conn_dst) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -400,17 +416,15 @@ int osmux_init(int role, struct mgcp_config *cfg)
{
int ret;
osmux_fd.cb = osmux_read_fd_cb;
osmux_fd.data = cfg;
osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, cfg, 0);
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port,
cfg->endp_dscp, cfg->endp_priority);
if (ret < 0) {
LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
cfg->osmux_addr, cfg->osmux_port);
return ret;
}
mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
osmux_fd.when |= OSMO_FD_READ;
ret = osmo_fd_register(&osmux_fd);
if (ret < 0) {
@@ -433,7 +447,7 @@ int osmux_init(int role, struct mgcp_config *cfg)
* \param[in] port portnumber of the remote OSMUX endpoint (in network byte order)
* \returns 0 on success, -1 on ERROR */
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
struct in_addr *addr, uint16_t port)
struct osmo_sockaddr *addr, uint16_t port)
{
/*! If osmux is enabled, initialize the output handler. This handler is
* used to reconstruct the RTP flow from osmux. The RTP SSRC is
@@ -444,9 +458,9 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
* overlapping RTP SSRC traveling to the BTSes behind the BSC,
* similarly, for flows traveling to the MSC.
*/
struct in_addr addr_unset = {};
struct in6_addr addr_unset = {};
static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
uint16_t osmux_dummy = endp->cfg->osmux_dummy;
uint16_t osmux_dummy = endp->trunk->cfg->osmux_dummy;
/* Check if osmux is enabled for the specified connection */
if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
@@ -457,13 +471,16 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
}
/* Wait until we have the connection information from MDCX */
if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0) {
if (memcmp(&conn->end.addr, &addr_unset,
conn->end.addr.u.sa.sa_family == AF_INET6 ?
sizeof(struct in6_addr) :
sizeof(struct in_addr)) == 0) {
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
"Osmux remote address/port still unknown\n");
return -1;
}
conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
conn->osmux.in = osmux_handle_lookup(conn, addr, port);
if (!conn->osmux.in) {
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
"Cannot allocate input osmux handle for conn:%s\n",
@@ -559,6 +576,7 @@ int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid)
* \returns bytes sent, -1 on error */
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
char ipbuf[INET6_ADDRSTRLEN];
struct osmux_hdr *osmuxh;
int buf_len;
struct in_addr addr_unset = {};
@@ -588,7 +606,8 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
"sending OSMUX dummy load to %s:%u CID %u\n",
inet_ntoa(conn->end.addr), ntohs(conn->end.rtp_port), conn->osmux.cid);
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
ntohs(conn->end.rtp_port), conn->osmux.cid);
return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
conn->end.rtp_port, (char*)osmuxh, buf_len);

File diff suppressed because it is too large Load Diff

View File

@@ -22,9 +22,14 @@
*
*/
#include <stdatomic.h>
#include <errno.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_protocol.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_ratectr.h>
static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
@@ -58,7 +63,6 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
{ "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
[MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
[MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = { "crcx:conn_rejected", "connection rejected by policy." },
[MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
@@ -90,8 +94,6 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
{ "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
[MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },
[MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
};
@@ -105,15 +107,12 @@ const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
[MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
[MGCP_DLCX_FAIL_WILDCARD] = { "dlcx:wildcard", "wildcard names in DLCX commands are unsupported." },
[MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
[MGCP_DLCX_FAIL_INVALID_CALLID] =
{ "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
[MGCP_DLCX_FAIL_INVALID_CONNID] =
{ "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
[MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },
[MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },
[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
};
@@ -126,9 +125,9 @@ const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
};
static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
[E1_I460_TRAU_RX_FAIL_CTR] = {"e1:rx_fail", "Inbound I.460 TRAU failures."},
[E1_I460_TRAU_TX_FAIL_CTR] = {"e1:tx_fail", "Outbound I.460 TRAU failures."},
[E1_I460_TRAU_MUX_EMPTY_CTR] = {"e1:i460", "Outbound I.460 MUX queue empty."}
[E1_I460_TRAU_RX_FAIL_CTR] = { "e1:rx_fail", "Inbound I.460 TRAU failures." },
[E1_I460_TRAU_TX_FAIL_CTR] = { "e1:tx_fail", "Outbound I.460 TRAU failures." },
[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
};
const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
@@ -147,83 +146,180 @@ const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
.ctr_desc = all_rtp_conn_rate_ctr_desc
};
static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
/*! allocate global rate counters
* (called once at startup).
* \param[in] cfg mgw configuration for which the rate counters are allocated.
* \returns 0 on success, -EINVAL on failure. */
int mgcp_ratectr_global_alloc(struct mgcp_config *cfg)
{
rate_ctr_group_free(rate_ctr_group);
return 0;
}
/*! allocate global rate counters into a given rate counter struct
* (called once at startup)
* \param[in] ctx talloc context.
* \param[out] ratectr struct that holds the counters
* \returns 0 on success, -EINVAL on failure */
int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr)
{
/* FIXME: Each new rate counter group requires a unique index. At the
* moment we generate an index using a counter, but perhaps there is
* a better way of assigning indices? */
static unsigned int general_rate_ctr_index = 0;
struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
static atomic_uint general_rate_ctr_index = 0;
char ctr_name[512];
if (ratectr->mgcp_general_ctr_group == NULL) {
ratectr->mgcp_general_ctr_group =
rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
rate_ctr_group_alloc(cfg, &mgcp_general_ctr_group_desc, general_rate_ctr_index++);
if (!ratectr->mgcp_general_ctr_group)
return -EINVAL;
talloc_set_destructor(ratectr->mgcp_general_ctr_group, free_rate_counter_group);
general_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s:general", cfg->domain);
rate_ctr_group_set_name(ratectr->mgcp_general_ctr_group, ctr_name);
}
return 0;
}
/*! allocate trunk specific rate counters into a given rate counter struct
* (called once on trunk initialization)
* \param[in] ctx talloc context.
* \param[out] ratectr struct that holds the counters
* \returns 0 on success, -EINVAL on failure */
int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr)
/*! free global rate counters
* (called once at process shutdown).
* \param[in] cfg mgw configuration for which the rate counters are allocated. */
void mgcp_ratectr_global_free(struct mgcp_config *cfg)
{
/* FIXME: see comment in mgcp_ratectr_global_alloc() */
static unsigned int crcx_rate_ctr_index = 0;
static unsigned int mdcx_rate_ctr_index = 0;
static unsigned int dlcx_rate_ctr_index = 0;
static unsigned int all_rtp_conn_rate_ctr_index = 0;
struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
if (ratectr->mgcp_general_ctr_group) {
rate_ctr_group_free(ratectr->mgcp_general_ctr_group);
ratectr->mgcp_general_ctr_group = NULL;
}
}
/*! allocate trunk specific rate counters
* (called once on trunk initialization).
* \param[in] trunk mgw trunk for which the rate counters are allocated.
* \returns 0 on success, -EINVAL on failure */
int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
{
struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
static atomic_uint crcx_rate_ctr_index = 0;
static atomic_uint mdcx_rate_ctr_index = 0;
static atomic_uint dlcx_rate_ctr_index = 0;
static atomic_uint all_rtp_conn_rate_ctr_index = 0;
char ctr_name[256];
if (ratectr->mgcp_crcx_ctr_group == NULL) {
ratectr->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
ratectr->mgcp_crcx_ctr_group =
rate_ctr_group_alloc(trunk, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index++);
if (!ratectr->mgcp_crcx_ctr_group)
return -EINVAL;
talloc_set_destructor(ratectr->mgcp_crcx_ctr_group, free_rate_counter_group);
crcx_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:crcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->mgcp_crcx_ctr_group, ctr_name);
}
if (ratectr->mgcp_mdcx_ctr_group == NULL) {
ratectr->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
ratectr->mgcp_mdcx_ctr_group =
rate_ctr_group_alloc(trunk, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index++);
if (!ratectr->mgcp_mdcx_ctr_group)
return -EINVAL;
talloc_set_destructor(ratectr->mgcp_mdcx_ctr_group, free_rate_counter_group);
mdcx_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:mdcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->mgcp_mdcx_ctr_group, ctr_name);
}
if (ratectr->mgcp_dlcx_ctr_group == NULL) {
ratectr->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
ratectr->mgcp_dlcx_ctr_group =
rate_ctr_group_alloc(trunk, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index++);
if (!ratectr->mgcp_dlcx_ctr_group)
return -EINVAL;
talloc_set_destructor(ratectr->mgcp_dlcx_ctr_group, free_rate_counter_group);
dlcx_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:dlcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->mgcp_dlcx_ctr_group, ctr_name);
}
if (ratectr->all_rtp_conn_stats == NULL) {
ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
all_rtp_conn_rate_ctr_index);
ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc,
all_rtp_conn_rate_ctr_index++);
if (!ratectr->all_rtp_conn_stats)
return -EINVAL;
talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group);
all_rtp_conn_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:rtp_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
}
if (ratectr->e1_stats == NULL) {
ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index);
/* E1 specific */
if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
ratectr->e1_stats = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
if (!ratectr->e1_stats)
return -EINVAL;
talloc_set_destructor(ratectr->e1_stats, free_rate_counter_group);
mdcx_rate_ctr_index++;
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:e1", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
rate_ctr_group_set_name(ratectr->e1_stats, ctr_name);
}
return 0;
}
/*! free trunk specific rate counters
* (called once when trunk is freed).
* \param[in] trunk mgw trunk on which the rate counters are allocated. */
void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
{
struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
if (ratectr->mgcp_crcx_ctr_group) {
rate_ctr_group_free(ratectr->mgcp_crcx_ctr_group);
ratectr->mgcp_crcx_ctr_group = NULL;
}
if (ratectr->mgcp_mdcx_ctr_group) {
rate_ctr_group_free(ratectr->mgcp_mdcx_ctr_group);
ratectr->mgcp_mdcx_ctr_group = NULL;
}
if (ratectr->mgcp_dlcx_ctr_group) {
rate_ctr_group_free(ratectr->mgcp_dlcx_ctr_group);
ratectr->mgcp_dlcx_ctr_group = NULL;
}
if (ratectr->all_rtp_conn_stats) {
rate_ctr_group_free(ratectr->all_rtp_conn_stats);
ratectr->all_rtp_conn_stats = NULL;
}
/* E1 specific */
if (ratectr->e1_stats) {
rate_ctr_group_free(ratectr->e1_stats);
ratectr->e1_stats = NULL;
}
}
const struct osmo_stat_item_desc trunk_stat_desc[] = {
[TRUNK_STAT_ENDPOINTS_TOTAL] = { "endpoints:total",
"Number of endpoints that exist on the trunk",
"", 60, 0 },
[TRUNK_STAT_ENDPOINTS_USED] = { "endpoints:used",
"Number of endpoints in use",
"", 60, 0 },
};
const struct osmo_stat_item_group_desc trunk_statg_desc = {
.group_name_prefix = "trunk",
.group_description = "mgw trunk",
.class_id = OSMO_STATS_CLASS_GLOBAL,
.num_items = ARRAY_SIZE(trunk_stat_desc),
.item_desc = trunk_stat_desc,
};
/*! allocate trunk specific stat items
* (called once on trunk initialization).
* \param[in] trunk for which the stat items are allocated.
* \returns 0 on success, -EINVAL on failure. */
int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk)
{
struct mgcp_stat_trunk *stats = &trunk->stats;
static unsigned int common_stat_index = 0;
char stat_name[256];
stats->common = osmo_stat_item_group_alloc(trunk, &trunk_statg_desc, common_stat_index);
if (!stats->common)
return -EINVAL;
snprintf(stat_name, sizeof(stat_name), "%s-%u:common", mgcp_trunk_type_strs_str(trunk->trunk_type),
trunk->trunk_nr);
osmo_stat_item_group_set_name(stats->common, stat_name);
common_stat_index++;
return 0;
}
/*! free trunk specific stat items
* (called once when trunk is freed).
* \param[in] trunk on which the stat items are allocated. */
void mgcp_stat_trunk_free(struct mgcp_trunk *trunk)
{
struct mgcp_stat_trunk *stats = &trunk->stats;
if (stats->common) {
osmo_stat_item_group_free(stats->common);
stats->common = NULL;
}
}

View File

@@ -21,6 +21,9 @@
*/
#include <osmocom/core/msgb.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
@@ -259,6 +262,42 @@ error:
return -EINVAL;
}
static int audio_ip_from_sdp(struct osmo_sockaddr *dst_addr, char *sdp)
{
bool is_ipv6;
char ipbuf[INET6_ADDRSTRLEN];
if (strncmp("c=IN IP", sdp, 7) != 0)
return -1;
sdp += 7;
if (*sdp == '6')
is_ipv6 = true;
else if (*sdp == '4')
is_ipv6 = false;
else
return -1;
sdp++;
if (*sdp != ' ')
return -1;
sdp++;
if (is_ipv6) {
/* 45 = INET6_ADDRSTRLEN -1 */
if (sscanf(sdp, "%45s", ipbuf) != 1)
return -1;
if (inet_pton(AF_INET6, ipbuf, &dst_addr->u.sin6.sin6_addr) != 1)
return -1;
dst_addr->u.sa.sa_family = AF_INET6;
} else {
/* 15 = INET_ADDRSTRLEN -1 */
if (sscanf(sdp, "%15s", ipbuf) != 1)
return -1;
if (inet_pton(AF_INET, ipbuf, &dst_addr->u.sin.sin_addr) != 1)
return -1;
dst_addr->u.sa.sa_family = AF_INET;
}
return 0;
}
/* Pick optional fmtp parameters by payload type, if there are no fmtp
* parameters, a nullpointer is returned */
static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
@@ -289,6 +328,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
unsigned int fmtp_used = 0;
struct mgcp_codec_param *codec_param;
char ipbuf[INET6_ADDRSTRLEN];
char *line;
unsigned int i;
void *tmp_ctx = talloc_new(NULL);
@@ -298,7 +338,6 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
int ptime, ptime2 = 0;
char audio_name[64];
int port, rc;
char ipv4[16];
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
@@ -355,13 +394,13 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
codecs_used = rc;
break;
case 'c':
if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
inet_aton(ipv4, &rtp->addr);
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
talloc_free(tmp_ctx);
return -1;
}
break;
default:
if (p->endp)
if (endp)
/* TODO: Check spec: We used the bare endpoint number before,
* now we use the endpoint name as a whole? Is this allowed? */
LOGP(DLMGCP, LOGL_NOTICE,
@@ -393,14 +432,14 @@ 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), inet_ntoa(rtp->addr),
ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
rtp->packet_duration_ms);
if (codecs_used == 0)
LOGPC(DLMGCP, LOGL_NOTICE, "none");
for (i = 0; i < codecs_used; i++) {
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
rtp->codecs[i].payload_type,
rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
LOGPC(DLMGCP, LOGL_NOTICE, " ");
}
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
@@ -529,6 +568,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
int local_port;
struct sdp_fmtp_param fmtp_params[1];
unsigned int fmtp_params_len = 0;
bool addr_is_v6;
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
@@ -536,19 +576,23 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
OSMO_ASSERT(addr);
/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
endp->trunk->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
&codec, &fmtp_extra,
(struct mgcp_conn_rtp *)conn);
audio_name = codec->audio_name;
payload_type = codec->payload_type;
addr_is_v6 = osmo_ip_str_type(addr) == AF_INET6;
rc = msgb_printf(sdp,
"v=0\r\n"
"o=- %s 23 IN IP4 %s\r\n"
"o=- %s 23 IN IP%c %s\r\n"
"s=-\r\n"
"c=IN IP4 %s\r\n"
"t=0 0\r\n", conn->conn->id, addr, addr);
"c=IN IP%c %s\r\n"
"t=0 0\r\n", conn->conn->id,
addr_is_v6 ? '6' : '4', addr,
addr_is_v6 ? '6' : '4', addr);
if (rc < 0)
goto buffer_too_small;
@@ -557,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->cfg->osmux_port;
local_port = endp->trunk->cfg->osmux_port;
else
local_port = conn->end.local_port;
rc = add_audio(sdp, payload_types, 1, local_port);

View File

@@ -28,12 +28,18 @@
#include <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_stat.h>
#include <osmocom/mgcp/mgcp_endp.h>
#include <osmocom/mgcp/mgcp_trunk.h>
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
#if defined(__has_attribute)
#if __has_attribute(no_sanitize)
__attribute__((no_sanitize("undefined")))
#endif
#endif
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
{
struct mgcp_rtp_state *state = &conn->state;
struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
*expected = state->stats.cycles + state->stats.max_seq;
*expected = *expected - state->stats.base_seq + 1;
@@ -74,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
int ploss;
int nchars;
struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
struct rate_ctr *octets_rx = &conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR];
struct rate_ctr *packets_tx = &conn->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR];
struct rate_ctr *octets_tx = &conn->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR];
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);
calc_loss(conn, &expected, &ploss);
jitter = calc_jitter(&conn->state);
@@ -93,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
str += nchars;
str_len -= nchars;
if (conn->conn->endp->cfg->osmux != OSMUX_USAGE_OFF) {
if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
/* Error Counter */
nchars = snprintf(str, str_len,
"\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,

View File

@@ -27,14 +27,31 @@
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_e1.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/core/stat_item.h>
/*! allocate trunk and add it (if required) to the trunk list.
const struct value_string mgcp_trunk_type_strs[] = {
{ MGCP_TRUNK_VIRTUAL, "virtual" },
{ MGCP_TRUNK_E1, "e1" },
{ 0, NULL }
};
/* Free trunk, this function is automatically called by talloc_free when the trunk is freed. It does not free the
* endpoints on the trunk, this must be done separately before freeing the trunk. */
static int trunk_free_talloc_destructor(struct mgcp_trunk *trunk)
{
llist_del(&trunk->entry);
mgcp_ratectr_trunk_free(trunk);
mgcp_stat_trunk_free(trunk);
return 0;
}
/*! allocate trunk and add it to the trunk list.
* (called once at startup by VTY).
* \param[in] cfg mgcp configuration.
* \param[in] ttype trunk type.
* \param[in] nr trunk number.
* \returns pointer to allocated trunk, NULL on failure. */
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
{
struct mgcp_trunk *trunk;
@@ -50,14 +67,16 @@ struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_typ
trunk->audio_send_ptime = 1;
trunk->audio_send_name = 1;
trunk->v.vty_number_endpoints = 32;
trunk->v.vty_number_endpoints = 512;
trunk->omit_rtcp = 0;
mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
llist_add_tail(&trunk->entry, &cfg->trunks);
mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
mgcp_ratectr_trunk_alloc(trunk);
mgcp_stat_trunk_alloc(trunk);
talloc_set_destructor(trunk, trunk_free_talloc_destructor);
return trunk;
}
@@ -104,7 +123,7 @@ int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
OSMO_ASSERT(number_endpoints < 65534);
/* allocate pointer array for the endpoints */
trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
trunk->endpoints = talloc_zero_array(trunk, struct mgcp_endpoint*,
number_endpoints);
if (!trunk->endpoints)
return -1;
@@ -121,7 +140,8 @@ int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
/* make the endpoints we just created available to the MGW code */
trunk->number_endpoints = number_endpoints;
osmo_stat_item_set(osmo_stat_item_group_get_item(trunk->stats.common, TRUNK_STAT_ENDPOINTS_TOTAL),
trunk->number_endpoints);
return 0;
}
@@ -165,7 +185,7 @@ int mgcp_trunk_equip(struct mgcp_trunk *trunk)
* \param[in] ttype trunk type.
* \param[in] nr trunk number.
* \returns pointer to trunk configuration, NULL on error. */
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
{
struct mgcp_trunk *trunk;
@@ -178,9 +198,9 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr
}
/* Made public for unit-testing, do not use from outside this file */
int e1_trunk_nr_from_epname(const char *epname)
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname)
{
unsigned long int trunk_nr;
unsigned long trunk_nr_temp;
size_t prefix_len;
char *str_trunk_nr_end;
@@ -189,13 +209,41 @@ int e1_trunk_nr_from_epname(const char *epname)
return -EINVAL;
errno = 0;
trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
if (errno == ERANGE || trunk_nr > 64
trunk_nr_temp = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
if (errno == ERANGE || trunk_nr_temp > 64
|| epname + prefix_len == str_trunk_nr_end
|| str_trunk_nr_end[0] != '/')
return -EINVAL;
else
return trunk_nr;
else {
*trunk_nr = (unsigned int)trunk_nr_temp;
return 0;
}
}
/* Check if the domain name, which is supplied with the endpoint name
* matches the configuration. */
static int check_domain_name(const char *epname, const struct mgcp_config *cfg)
{
char *domain_to_check;
domain_to_check = strstr(epname, "@");
if (!domain_to_check) {
LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
epname, cfg->domain);
return -EINVAL;
}
/* Accept any domain if configured as "*" */
if (!strcmp(cfg->domain, "*"))
return 0;
if (strcmp(domain_to_check+1, cfg->domain) != 0) {
LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
epname, cfg->domain);
return -EINVAL;
}
return 0;
}
/*! Find a trunk by the trunk prefix in the endpoint name.
@@ -206,18 +254,23 @@ struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char
{
size_t prefix_len;
char epname_lc[MGCP_ENDPOINT_MAXLEN];
int trunk_nr;
unsigned int trunk_nr;
int rc;
osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
epname = epname_lc;
/* All endpoint names require a domain as suffix */
if (check_domain_name(epname, cfg))
return NULL;
prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
}
trunk_nr = e1_trunk_nr_from_epname(epname);
if (trunk_nr >= 0)
rc = e1_trunk_nr_from_epname(&trunk_nr, epname);
if (rc == 0)
return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
/* Earlier versions of osmo-mgw were accepting endpoint names

File diff suppressed because it is too large Load Diff

View File

@@ -60,6 +60,8 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/misc.h>
#include <osmocom/vty/cpu_sched_vty.h>
#include <osmocom/abis/abis.h>
#include "../../bscconfig.h"
@@ -91,17 +93,45 @@ const char *osmomgw_copyright =
static char *config_file = "osmo-mgw.cfg";
/* used by msgb and mgcp */
void *tall_bsc_ctx = NULL;
void *tall_mgw_ctx = NULL;
static void print_help()
{
printf("Some useful help...\n");
printf("Some useful options:\n");
printf(" -h --help is printing this text.\n");
printf(" -c --config-file filename The config file to use.\n");
printf(" -s --disable-color\n");
printf(" -D --daemonize Fork the process into a background daemon\n");
printf(" -V --version Print the version number\n");
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
printf("\nVTY reference generation:\n");
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
}
static void handle_long_options(const char *prog_name, const int long_option)
{
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
switch (long_option) {
case 1:
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
if (vty_ref_mode < 0) {
fprintf(stderr, "%s: Unknown VTY reference generation "
"mode '%s'\n", prog_name, optarg);
exit(2);
}
break;
case 2:
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
exit(0);
default:
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
exit(2);
}
}
static void handle_options(int argc, char **argv)
@@ -115,7 +145,8 @@ static void handle_options(int argc, char **argv)
{"daemonize", 0, 0, 'D'},
{"version", 0, 0, 'V'},
{"disable-color", 0, 0, 's'},
{"vty-ref-xml", 0, &long_option, 1},
{"vty-ref-mode", 1, &long_option, 1},
{"vty-ref-xml", 0, &long_option, 2},
{0, 0, 0, 0},
};
@@ -130,16 +161,10 @@ static void handle_options(int argc, char **argv)
exit(0);
break;
case 0:
switch (long_option) {
case 1:
vty_dump_xml_ref(stdout);
exit(0);
default:
fprintf(stderr, "error parsing cmdline options\n");
exit(2);
}
handle_long_options(argv[0], long_option);
break;
case 'c':
config_file = talloc_strdup(tall_bsc_ctx, optarg);
config_file = talloc_strdup(tall_mgw_ctx, optarg);
break;
case 's':
log_set_use_color(osmo_stderr_target, 0);
@@ -177,7 +202,7 @@ static int mgcp_rsip_cb(struct mgcp_trunk *trunk)
static int read_call_agent(struct osmo_fd *fd, unsigned int what)
{
struct sockaddr_in addr;
struct osmo_sockaddr addr;
socklen_t slen = sizeof(addr);
struct msgb *msg;
struct msgb *resp;
@@ -203,14 +228,14 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
msgb_reset(msg);
if (resp) {
sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, &addr.u.sa, sizeof(addr));
msgb_free(resp);
}
/* reset endpoints */
if (reset_endpoints) {
LOGP(DLMGCP, LOGL_NOTICE,
"Asked to reset endpoints: %d/%d\n",
"Asked to reset endpoints: %u/%d\n",
reset_trunk->trunk_nr, reset_trunk->trunk_type);
/* reset flag */
@@ -218,7 +243,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
/* Walk over all endpoints and trigger a release, this will release all
* endpoints, possible open connections are forcefully dropped */
for (i = 1; i < reset_trunk->number_endpoints; ++i)
for (i = 0; i < reset_trunk->number_endpoints; ++i)
mgcp_endp_release(reset_trunk->endpoints[i]);
}
@@ -290,20 +315,24 @@ int main(int argc, char **argv)
unsigned int flags;
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
vty_info.tall_ctx = tall_bsc_ctx;
tall_mgw_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
vty_info.tall_ctx = tall_mgw_ctx;
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
osmo_init_ignore_signals();
osmo_init_logging2(tall_bsc_ctx, &log_info);
libosmo_abis_init(tall_bsc_ctx);
osmo_init_logging2(tall_mgw_ctx, &log_info);
libosmo_abis_init(tall_mgw_ctx);
cfg = mgcp_config_alloc();
if (!cfg)
return -1;
vty_info.copyright = osmomgw_copyright;
vty_info.usr_attr_desc[MGW_CMD_ATTR_NEWCONN] = \
"This command applies when a new connection is created";
vty_info.usr_attr_letters[MGW_CMD_ATTR_NEWCONN] = 'n';
vty_init(&vty_info);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
@@ -311,18 +340,19 @@ int main(int argc, char **argv)
mgcp_vty_init();
ctrl_vty_init(cfg);
e1inp_vty_init();
osmo_cpu_sched_vty_init(tall_mgw_ctx);
handle_options(argc, argv);
rate_ctr_init(tall_bsc_ctx);
osmo_stats_init(tall_bsc_ctx);
rate_ctr_init(tall_mgw_ctx);
osmo_stats_init(tall_mgw_ctx);
rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
if (rc < 0)
return rc;
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(tall_bsc_ctx, NULL,
rc = telnet_init_dynif(tall_mgw_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
if (rc < 0)
return rc;
@@ -339,12 +369,12 @@ int main(int argc, char **argv)
/* we need to bind a socket */
flags = OSMO_SOCK_F_BIND;
if (cfg->call_agent_addr)
if (strlen(cfg->call_agent_addr))
flags |= OSMO_SOCK_F_CONNECT;
rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
cfg->source_addr, cfg->source_port,
cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
cfg->call_agent_addr, strlen(cfg->call_agent_addr) ? 2727 : 0, flags);
if (rc < 0) {
perror("Gateway failed to bind");
return -1;

View File

@@ -30,10 +30,12 @@
#include <osmocom/mgcp/mgcp_trunk.h>
#include <osmocom/mgcp/mgcp_sdp.h>
#include <osmocom/mgcp/mgcp_codec.h>
#include <osmocom/mgcp/mgcp_network.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/socket.h>
#include <string.h>
#include <limits.h>
#include <dlfcn.h>
@@ -126,7 +128,7 @@ static void test_strline(void)
"a=fmtp:126 0/1/2\r\n" \
"a=ptime:40\r\n"
#define MDCX4 \
#define MDCX4_ADDR0000 \
"MDCX 18983216 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
@@ -141,6 +143,24 @@ static void test_strline(void)
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_ADDR0000_RET \
"527 18983216 FAIL\r\n"
#define MDCX4 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_RET(Ident) \
"200 " Ident " OK\r\n" \
"\r\n" \
@@ -166,45 +186,45 @@ static void test_strline(void)
"a=ptime:40\r\n"
#define MDCX4_PT1 \
"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"M: SENDRECV\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-40, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_PT2 \
"MDCX 18983218 1@mgw MGCP 1.0\r\n" \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20-20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_PT3 \
"MDCX 18983219 1@mgw MGCP 1.0\r\n" \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"M: sendrecv\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
@@ -212,47 +232,47 @@ static void test_strline(void)
/* Test different upper/lower case in options */
#define MDCX4_PT4 \
"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"m: sendrecv\r" \
"c: 2\r\n" \
"i: %s\r\n" \
"l: A:amr, NT:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_SO \
"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"M: sendonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n" \
"\n" \
"v=0\r\n" \
"o=- %s 23 IN IP4 0.0.0.0\r\n" \
"c=IN IP4 0.0.0.0\r\n" \
"o=- %s 23 IN IP4 5.6.7.8\r\n" \
"c=IN IP4 5.6.7.8\r\n" \
"t=0 0\r\n" \
"m=audio 4441 RTP/AVP 99\r\n" \
"a=rtpmap:99 AMR/8000\r\n" \
"a=ptime:40\r\n"
#define MDCX4_RO \
"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"M: recvonly\r" \
"C: 2\r\n" \
"I: %s\r\n" \
"L: p:20, a:AMR, nt:IN\r\n"
#define MDCX_TOO_LONG_CI \
"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
"MDCX 18983224 1@mgw MGCP 1.0\r\n" \
"I: 123456789012345678901234567890123\n"
#define MDCX_TOO_LONG_CI_RET "510 18983223 FAIL\r\n"
#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
#define SHORT2 "CRCX 1"
#define SHORT2_RET "510 000000 FAIL\r\n"
@@ -540,13 +560,14 @@ static const struct mgcp_test tests[] = {
{"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
{"CRCX", CRCX, CRCX_RET, 97},
{"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
{"MDCX4", MDCX4, MDCX4_RET("18983216"), 99},
{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
{"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983220"), 99},
{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983221"), 99},
{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983222"), PTYPE_IGNORE},
{"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
{"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
{"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
{"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
{"EMPTY", EMPTY, EMPTY_RET},
@@ -593,29 +614,6 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
return msg;
}
static char last_endpoint[MGCP_ENDPOINT_MAXLEN];
static int mgcp_test_policy_cb(struct mgcp_endpoint *endp,
int state, const char *transaction_id)
{
unsigned int i;
struct mgcp_trunk *trunk;
fprintf(stderr, "Policy CB got state %d on endpoint %s\n",
state, endp->name);
trunk = endp->trunk;
last_endpoint[0] = '\0';
for (i = 0; i < trunk->number_endpoints; i++) {
if (strcmp(endp->name, trunk->endpoints[i]->name) == 0)
osmo_strlcpy(last_endpoint, trunk->endpoints[i]->name,
sizeof(last_endpoint));
}
return MGCP_POLICY_CONT;
}
#define MGCP_DUMMY_LOAD 0x23
static int dummy_packets = 0;
/* override and forward */
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
@@ -625,13 +623,18 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
if (len == 1 && ((const char *)buf)[0] == MGCP_DUMMY_LOAD) {
if (len == sizeof(rtp_dummy_payload)
&& memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
fprintf(stderr,
"Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
dest_host, dest_port, len, osmo_hexdump(buf, len));
dummy_packets += 1;
}
/* Make sure address+port are valid */
OSMO_ASSERT(dest_host);
OSMO_ASSERT(dest_port);
return len;
}
@@ -767,13 +770,13 @@ static void test_messages(void)
struct mgcp_conn_rtp *conn = NULL;
char last_conn_id[256];
int rc;
char *last_endpoint = mgcp_debug_get_last_endpoint_name();
cfg = mgcp_config_alloc();
trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
trunk->v.vty_number_endpoints = 64;
mgcp_trunk_equip(trunk);
cfg->policy_cb = mgcp_test_policy_cb;
memset(last_conn_id, 0, sizeof(last_conn_id));
@@ -785,7 +788,6 @@ static void test_messages(void)
printf("\n================================================\n");
printf("Testing %s\n", t->name);
last_endpoint[0] = '\0';
dummy_packets = 0;
osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
@@ -958,7 +960,7 @@ static void test_retransmission(void)
static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
{
ptrdiff_t tone = _tone;
endp->cfg->data = (void *)tone;
endp->trunk->cfg->data = (void *)tone;
return 0;
}
@@ -1040,20 +1042,19 @@ static void test_packet_loss_calc(void)
int i;
struct mgcp_endpoint endp;
struct mgcp_endpoint *endpoints[1];
struct mgcp_config cfg = {0};
struct mgcp_trunk trunk;
struct mgcp_config *cfg;
struct mgcp_trunk *trunk;
printf("Testing packet loss calculation.\n");
memset(&endp, 0, sizeof(endp));
memset(&trunk, 0, sizeof(trunk));
endp.cfg = &cfg;
cfg = mgcp_config_alloc();
trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
endp.type = &ep_typeset.rtp;
trunk.v.vty_number_endpoints = 1;
trunk.endpoints = endpoints;
trunk.endpoints[0] = &endp;
endp.trunk = &trunk;
trunk->v.vty_number_endpoints = 1;
trunk->endpoints = endpoints;
trunk->endpoints[0] = &endp;
endp.trunk = trunk;
INIT_LLIST_HEAD(&endp.conns);
for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
@@ -1070,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 = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
state->stats.initialized = 1;
state->stats.base_seq = pl_test_dat[i].base_seq;
@@ -1091,6 +1092,8 @@ static void test_packet_loss_calc(void)
mgcp_conn_free_all(&endp);
}
talloc_free(trunk);
talloc_free(cfg);
}
int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
@@ -1257,24 +1260,28 @@ struct rtp_packet_info test_rtp_packets1[] = {
/* RTP: SeqNo=1002, TS=160320 */
{2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
"\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
/* RTP: SeqNo=1003, TS=180320, Marker */
{2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
"\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
/* RTP: SeqNo=1004, TS=180480 */
{2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
"\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
/* RTP: SeqNo=1005, TS=180480, 10ms too late */
{2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
"\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
};
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
struct mgcp_rtp_state *state,
struct mgcp_rtp_end *rtp_end,
struct sockaddr_in *addr, struct msgb *msg);
static void test_packet_error_detection(int patch_ssrc, int patch_ts)
{
int i;
struct mgcp_trunk trunk;
struct mgcp_trunk *trunk;
struct mgcp_endpoint endp;
struct mgcp_endpoint *endpoints[1];
struct mgcp_config cfg = {0};
struct mgcp_config *cfg;
struct mgcp_rtp_state state;
struct mgcp_rtp_end *rtp;
struct sockaddr_in addr = { 0 };
struct osmo_sockaddr addr = { 0 };
uint32_t last_ssrc = 0;
uint32_t last_timestamp = 0;
uint32_t last_seqno = 0;
@@ -1289,7 +1296,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
patch_ssrc ? ", patch SSRC" : "",
patch_ts ? ", patch timestamps" : "");
memset(&trunk, 0, sizeof(trunk));
cfg = mgcp_config_alloc();
trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
memset(&endp, 0, sizeof(endp));
memset(&state, 0, sizeof(state));
@@ -1298,16 +1306,15 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
state.in_stream.err_ts_ctr = &test_ctr_in;
state.out_stream.err_ts_ctr = &test_ctr_out;
endp.cfg = &cfg;
endp.type = &ep_typeset.rtp;
trunk.v.vty_number_endpoints = 1;
trunk.endpoints = endpoints;
trunk.endpoints[0] = &endp;
trunk.force_constant_ssrc = patch_ssrc;
trunk.force_aligned_timing = patch_ts;
trunk->v.vty_number_endpoints = 1;
trunk->endpoints = endpoints;
trunk->endpoints[0] = &endp;
trunk->force_constant_ssrc = patch_ssrc;
trunk->force_aligned_timing = patch_ts;
endp.trunk = &trunk;
endp.trunk = trunk;
INIT_LLIST_HEAD(&endp.conns);
_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
@@ -1366,6 +1373,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
force_monotonic_time_us = -1;
mgcp_conn_free_all(&endp);
talloc_free(trunk);
talloc_free(cfg);
}
static void test_multilple_codec(void)
@@ -1377,6 +1386,7 @@ static void test_multilple_codec(void)
struct in_addr addr;
struct mgcp_conn_rtp *conn = NULL;
char conn_id[256];
char *last_endpoint = mgcp_debug_get_last_endpoint_name();
printf("Testing multiple payload types\n");
@@ -1384,7 +1394,6 @@ static void test_multilple_codec(void)
trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
trunk->v.vty_number_endpoints = 64;
mgcp_trunk_equip(trunk);
cfg->policy_cb = mgcp_test_policy_cb;
/* Allocate endpoint 1@mgw with two codecs */
last_endpoint[0] = '\0';
@@ -1486,7 +1495,8 @@ static void test_multilple_codec(void)
OSMO_ASSERT(conn->end.rtp_port == htons(16434));
memset(&addr, 0, sizeof(addr));
inet_aton("8.8.8.8", &addr);
OSMO_ASSERT(conn->end.addr.s_addr == addr.s_addr);
OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
/* Check what happens without that flag */
@@ -1545,24 +1555,24 @@ static void test_no_cycle(void)
OSMO_ASSERT(conn->state.stats.initialized == 0);
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
OSMO_ASSERT(conn->state.stats.initialized == 1);
OSMO_ASSERT(conn->state.stats.cycles == 0);
OSMO_ASSERT(conn->state.stats.max_seq == 0);
mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
OSMO_ASSERT(conn->state.stats.initialized == 1);
OSMO_ASSERT(conn->state.stats.cycles == 0);
OSMO_ASSERT(conn->state.stats.max_seq == 1);
/* now jump.. */
mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
OSMO_ASSERT(conn->state.stats.initialized == 1);
OSMO_ASSERT(conn->state.stats.cycles == 0);
OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
/* and wrap */
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
OSMO_ASSERT(conn->state.stats.initialized == 1);
OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
OSMO_ASSERT(conn->state.stats.max_seq == 0);
@@ -1585,8 +1595,6 @@ static void test_no_name(void)
trunk->audio_send_name = 0;
mgcp_trunk_equip(trunk);
cfg->policy_cb = mgcp_test_policy_cb;
inp = create_msg(CRCX, NULL);
msg = mgcp_handle_message(cfg, inp);
@@ -2119,46 +2127,95 @@ void test_conn_id_matching()
void test_e1_trunk_nr_from_epname()
{
int trunk_nr;
unsigned int trunk_nr;
int rc;
/* Note: e1_trunk_nr_from_epname does not check the text
* after the E1 trunk number, after the delimiter
* character "/" arbitrary text may follow. */
trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
OSMO_ASSERT(trunk_nr == 0);
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
OSMO_ASSERT(trunk_nr == 1);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
OSMO_ASSERT(trunk_nr == 2);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
OSMO_ASSERT(trunk_nr == 3);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
OSMO_ASSERT(trunk_nr == 3);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
OSMO_ASSERT(trunk_nr == 24);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
OSMO_ASSERT(rc == 0);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
OSMO_ASSERT(trunk_nr == 64);
OSMO_ASSERT(rc == 0);
/* The following endpoint strings should fail, either the
* trunk number exceeds the valid range or the trunk prefix
* is wrong. Also when the delimiter character "/" at the
* end of the trunk is wrong the parsing should fail. */
trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
OSMO_ASSERT(trunk_nr == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
OSMO_ASSERT(rc == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
OSMO_ASSERT(rc == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
OSMO_ASSERT(rc == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
OSMO_ASSERT(rc == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
OSMO_ASSERT(rc == -EINVAL);
rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
OSMO_ASSERT(rc == -EINVAL);
return;
}
void test_mgcp_is_rtp_dummy_payload()
{
/* realistic rtp packet */
static const char rtp_payload[] =
{ 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
0x24 };
struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
struct msgb *msg_dummy_rtp =
msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
uint8_t *buf;
/* Dummy RTP packet */
buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
/* Normal RTP packet */
buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
/* Dummy RTP packet with normal RTP packet attached, this must not be
* recognized as Dummy RTP packet */
buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
msgb_free(msg_dummy);
msgb_free(msg_rtp);
msgb_free(msg_dummy_rtp);
}
int main(int argc, char **argv)
{
void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
@@ -2185,6 +2242,7 @@ int main(int argc, char **argv)
test_mgcp_codec_pt_translate();
test_conn_id_matching();
test_e1_trunk_nr_from_epname();
test_mgcp_is_rtp_dummy_payload();
OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);

View File

@@ -97,7 +97,7 @@ Response matches our expectations.
Dummy packets: 2
================================================
Testing MDCX4
Testing MDCX4_ADDR000
creating message from statically defined input:
---------8<---------
MDCX 18983216 1@mgw MGCP 1.0
@@ -113,6 +113,29 @@ m=audio 4441 RTP/AVP 99
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
---------8<---------
checking response:
using message as statically defined for comparison
Response matches our expectations.
(response does not contain a connection id)
================================================
Testing MDCX4
creating message from statically defined input:
---------8<---------
MDCX 18983217 1@mgw MGCP 1.0
M: sendrecv
C: 2
I: %s
L: p:20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
t=0 0
m=audio 4441 RTP/AVP 99
a=rtpmap:99 AMR/8000
a=ptime:40
---------8<---------
@@ -124,14 +147,14 @@ Dummy packets: 2
================================================
Testing MDCX4_PT1
---------8<---------
creating message from statically defined input:
---------8<---------
MDCX 18983218 1@mgw MGCP 1.0
M: SENDRECV
C: 2
I: %s
v=0
L: p:20-40, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
c=IN IP4 5.6.7.8
@@ -148,14 +171,14 @@ Dummy packets: 2
Dummy packets: 2
================================================
creating message from statically defined input:
Testing MDCX4_PT2
creating message from statically defined input:
---------8<---------
MDCX 18983219 1@mgw MGCP 1.0
M: sendrecv
C: 2
L: p:20-20, a:AMR, nt:IN
I: %s
L: p:20-20, a:AMR, nt:IN
v=0
o=- %s 23 IN IP4 5.6.7.8
@@ -172,14 +195,14 @@ Dummy packets: 2
(response contains a connection id)
Dummy packets: 2
Testing MDCX4_PT3
================================================
Testing MDCX4_PT3
creating message from statically defined input:
---------8<---------
MDCX 18983220 1@mgw MGCP 1.0
M: sendrecv
I: %s
L: a:AMR, nt:IN
C: 2
I: %s
L: a:AMR, nt:IN
v=0
@@ -196,14 +219,14 @@ Dummy packets: 2
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
================================================
================================================
Testing MDCX4_PT4
creating message from statically defined input:
---------8<---------
MDCX 18983221 1@mgw MGCP 1.0
c: 2
i: %s
m: sendrecv
c: 2
i: %s
l: A:amr, NT:IN
@@ -220,14 +243,14 @@ Dummy packets: 2
using message with patched conn_id for comparison
Response matches our expectations.
(response contains a connection id)
Dummy packets: 2
================================================
Testing MDCX4_SO
creating message from statically defined input:
---------8<---------
M: sendonly
C: 2
MDCX 18983222 1@mgw MGCP 1.0
M: sendonly
C: 2
I: %s
L: p:20, a:AMR, nt:IN
@@ -243,7 +266,7 @@ Response matches our expectations.
---------8<---------
checking response:
using message with patched conn_id for comparison
(response contains a connection id)
Response matches our expectations.
(response contains a connection id)
================================================
@@ -441,7 +464,6 @@ checking response:
Response matches our expectations.
(response does not contain a connection id)
Testing CRCX
================================================
Testing CRCX
creating message from statically defined input:
@@ -470,7 +492,7 @@ Dummy packets: 2
c=IN IP4 123.12.12.123
m=audio 5904 RTP/AVP 97
a=rtpmap:97 GSM-EFR/8000
a=ptime:40
---------8<---------
checking response:
@@ -770,6 +792,15 @@ Stats: Jitter = 0, Transit = -144000
Stats: Jitter = 24, Transit = -32888
In TS: 36728, dTS: 160, Seq: 24
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 22, Transit = -32888
In TS: 36888, dTS: 160, Seq: 25
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 21, Transit = -32888
In TS: 160000, dTS: 0, Seq: 1000
Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160160, dTS: 160, Seq: 1001
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160320, dTS: 160, Seq: 1002
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
@@ -864,6 +895,15 @@ Stats: Jitter = 0, Transit = -144000
In TS: 36728, dTS: 160, Seq: 24
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 22, Transit = -32888
In TS: 36888, dTS: 160, Seq: 25
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 21, Transit = -32888
Output SSRC changed to 50607080
In TS: 160000, dTS: 0, Seq: 1000
Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160160, dTS: 160, Seq: 1001
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160320, dTS: 160, Seq: 1002
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
@@ -958,6 +998,15 @@ Stats: Jitter = 0, Transit = -144000
In TS: 36728, dTS: 160, Seq: 24
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 22, Transit = -32888
In TS: 36888, dTS: 160, Seq: 25
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 21, Transit = -32888
Output SSRC changed to 50607080
In TS: 160000, dTS: 0, Seq: 1000
Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160160, dTS: 160, Seq: 1001
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160320, dTS: 160, Seq: 1002
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
@@ -1050,6 +1099,15 @@ Stats: Jitter = 0, Transit = -144000
Stats: Jitter = 24, Transit = -32888
In TS: 36728, dTS: 160, Seq: 24
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 22, Transit = -32888
In TS: 36888, dTS: 160, Seq: 25
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 21, Transit = -32888
In TS: 160000, dTS: 0, Seq: 1000
Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160160, dTS: 160, Seq: 1001
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
Stats: Jitter = 0, Transit = -144000
In TS: 160320, dTS: 160, Seq: 1002
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0

View File

@@ -294,11 +294,23 @@ void test_mgcp_msg(void)
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
memset(audio_ip_overflow, 'X', sizeof(audio_ip_overflow));
audio_ip_overflow[1] = '.';
audio_ip_overflow[sizeof(audio_ip_overflow) - 1] = '\0';
mgcp_msg.audio_ip = audio_ip_overflow;
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
OSMO_ASSERT(msg == NULL);
printf("IPv6 test:\n");
mgcp_msg.verb = MGCP_VERB_MDCX;
mgcp_msg.presence =
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
mgcp_msg.audio_ip = "2001:db8:1::ab9:c0a8:102";
mgcp->actual.remote_addr = "::1";
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
printf("%s\n", (char *)msg->data);
printf("\n");
msgb_free(msg);
}
@@ -413,6 +425,66 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
"m=audio 23\r\n",
.expect_rc = 0,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 1.2.3.4\r\n",
.expect_params = {
.audio_ip = "1.2.3.4",
},
.expect_rc = 0,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP6 2001:db8:1::ab9:c0a8:102\r\n",
.expect_params = {
.audio_ip = "2001:db8:1::ab9:c0a8:102",
},
.expect_rc = 0,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP6 1.2.3.4\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 ::1\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 notanip\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 1.2.3.4.5.6\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 1.2 .3\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 1.2 .3\r\n",
.expect_rc = -22,
},
{
.body = "some mgcp header data\r\nand header params"
"\r\n\r\n"
"c=IN IP4 \r\n",
.expect_rc = -22,
},
};
void test_sdp_section_start()
@@ -443,7 +515,12 @@ void test_sdp_section_start()
continue;
}
fprintf(stderr, "got audio_port=%u\n", t->expect_params.audio_port);
fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
failures++;
}
fprintf(stderr, "got audio_port=%u\n", r->audio_port);
if (r->audio_port != t->expect_params.audio_port) {
fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
failures++;
@@ -612,9 +689,10 @@ int main(int argc, char **argv)
ctx = talloc_named_const(NULL, 1, "mgcp_client_test");
msgb_talloc_ctx_init(ctx, 0);
osmo_init_logging2(ctx, &log_info);
log_set_print_filename(osmo_stderr_target, 0);
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);

View File

@@ -1,80 +1,138 @@
DLMGCP MGCP client: using endpoint domain '@mgw'
DLMGCP message buffer to small, can not generate MGCP message
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
test_mgcp_client_cancel():
DLMGCP MGCP client: using endpoint domain '@mgw'
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
- composed msg with trans_id=1
- not in queue yet, cannot cancel yet
DLMGCP Cannot cancel, no such transaction: 1
DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
- enqueue
- cancel succeeds
DLMGCP Canceled transaction 1
DLMGCP MGW(mgw) Canceled transaction 1
- late response gets discarded
DLMGCP Cannot find matching MGCP transaction for trans_id 1
DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
- canceling again does nothing
DLMGCP Cannot cancel, no such transaction: 1
DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
test_mgcp_client_cancel() done
test_sdp_section_start() test [0]:
body: ""
DLMGCP MGCP response contains no SDP parameters
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [1]:
body: "\n\n"
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [2]:
body: "\r\n\r\n"
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [3]:
body: "\n\r\n\r"
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [4]:
body: "some mgcp header data\r\nand header params\n\nm=audio 23\r\n"
got rc=0
got audio_ip=""
got audio_port=23
test_sdp_section_start() test [5]:
body: "some mgcp header data\r\nand header params\r\n\r\nm=audio 23\r\n"
got rc=0
got audio_ip=""
got audio_port=23
test_sdp_section_start() test [6]:
body: "some mgcp header data\r\nand header params\n\r\n\rm=audio 23\r\n"
got rc=0
got audio_ip=""
got audio_port=23
test_sdp_section_start() test [7]:
body: "some mgcp header data\r\nand header params\n\r\nm=audio 23\r\n"
DLMGCP MGCP response contains no SDP parameters
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [8]:
body: "some mgcp header data\r\nand header params\r\n\rm=audio 23\r\n"
DLMGCP MGCP response contains no SDP parameters
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [9]:
body: "some mgcp header data\r\nand header params\n\r\rm=audio 23\r\n"
DLMGCP MGCP response contains no SDP parameters
got rc=0
got audio_ip=""
got audio_port=0
test_sdp_section_start() test [10]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4\r\n"
got rc=0
got audio_ip="1.2.3.4"
got audio_port=0
test_sdp_section_start() test [11]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 2001:db8:1::ab9:c0a8:102\r\n"
got rc=0
got audio_ip="2001:db8:1::ab9:c0a8:102"
got audio_port=0
test_sdp_section_start() test [12]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 1.2.3.4\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [13]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 ::1\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [14]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 notanip\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [15]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4.5.6\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [16]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [17]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
test_sdp_section_start() test [18]:
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 \r\n"
DLMGCP Failed to parse MGCP response header (audio ip)
got rc=-22
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
DLMGCP MGCP client: using endpoint domain '@mgw'
DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
Done

View File

@@ -109,6 +109,20 @@ M: sendrecv
X-Osmux: 2
Overfolow test:
IPv6 test:
MDCX 19 23@mgw MGCP 1.0
C: 2f
I: 11
M: sendrecv
v=0
o=- 2f 23 IN IP6 ::1
s=-
c=IN IP6 2001:db8:1::ab9:c0a8:102
t=0 0
m=audio 1234 RTP/AVP 3
a=ptime:20
test_mgcp_client_cancel():
@@ -149,6 +163,24 @@ test_sdp_section_start() test [7]:
test_sdp_section_start() test [8]:
test_sdp_section_start() test [9]:
test_sdp_section_start() test [10]:
test_sdp_section_start() test [11]:
test_sdp_section_start() test [12]:
test_sdp_section_start() test [13]:
test_sdp_section_start() test [14]:
test_sdp_section_start() test [15]:
test_sdp_section_start() test [16]:
test_sdp_section_start() test [17]:
test_sdp_section_start() test [18]:
110 => 96
111 => 97
112 => 98