MT#61352 support signalling templates

Change-Id: If5624e3294bff7f677bdb08f98ea920c3b5f929a
pull/1884/head
Richard Fuchs 1 year ago
parent d48e028675
commit b8a915246f

@ -36,6 +36,7 @@ static pcre2_code *streams_re;
bool trust_address_def;
bool dtls_passive_def;
str_case_value_ht rtpe_signalling_templates;
enum basic_errors {
NG_ERROR_NO_SDP_BODY = 1,
@ -1453,6 +1454,7 @@ static void call_ng_received_from_iter(str *key, unsigned int i, helper_arg arg)
break;
}
}
void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) {
str s = STR_NULL;
sdp_ng_flags *out = arg.flags;
@ -1977,6 +1979,17 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
call_ng_flags_str_list(parser, value, ng_t38_option, out);
break;
#endif
case CSH_LOOKUP("template"):;
str *tplate = t_hash_table_lookup(rtpe_signalling_templates, &s);
if (!tplate) {
ilog(LOG_WARN, "Templates for signalling flags '" STR_FORMAT "' not found",
STR_FMT(&s));
break;
}
// naive approach: just parse them out every time
// TODO: improve this by pre-parsing the flags at startup
parse_rtpp_flags(tplate, out);
break;
case CSH_LOOKUP("to-interface"):
out->direction[1] = s;
break;
@ -3999,9 +4012,25 @@ void call_interfaces_free(void) {
pcre2_code_free(streams_re);
streams_re= NULL;
}
t_hash_table_destroy(rtpe_signalling_templates);
}
static void parse_templates(GHashTable *templates) {
if (!templates)
return;
GHashTableIter iter;
g_hash_table_iter_init(&iter, templates);
void *keyp, *valuep;
while (g_hash_table_iter_next(&iter, &keyp, &valuep)) {
char *key = keyp;
char *value = valuep;
t_hash_table_insert(rtpe_signalling_templates, str_dup(STR_PTR(key)), str_dup(STR_PTR(value)));
}
}
int call_interfaces_init(void) {
int call_interfaces_init(GHashTable *templates) {
int errcode;
PCRE2_SIZE erroff;
@ -4015,5 +4044,8 @@ int call_interfaces_init(void) {
if (!streams_re)
return -1;
rtpe_signalling_templates = str_case_value_ht_new();
parse_templates(templates);
return 0;
}

@ -485,7 +485,7 @@ static void release_listeners(GQueue *q) {
}
static void options(int *argc, char ***argv) {
static void options(int *argc, char ***argv, GHashTable *templates) {
g_autoptr(char_p) if_a = NULL;
g_autoptr(char_p) ks_a = NULL;
unsigned long uint_keyspace_db;
@ -533,6 +533,7 @@ static void options(int *argc, char ***argv) {
g_autoptr(char) nftables_family = NULL;
#endif
g_autoptr(char) redis_format = NULL;
g_autoptr(char) templates_section = NULL;
GOptionEntry e[] = {
{ "table", 't', 0, G_OPTION_ARG_INT, &rtpe_config.kernel_table, "Kernel table to use", "INT" },
@ -547,6 +548,7 @@ static void options(int *argc, char ***argv) {
{ "nftables-status",0, 0, G_OPTION_ARG_NONE, &nftables_status, "Check nftables rules, print result and exit", NULL },
#endif
{ "interface", 'i', 0, G_OPTION_ARG_STRING_ARRAY,&if_a, "Local interface for RTP", "[NAME/]IP[!IP]"},
{ "templates", 0, 0, G_OPTION_ARG_STRING, &templates_section, "Config section to read signalling templates from ", "STR"},
{ "save-interface-ports",'S', 0, G_OPTION_ARG_NONE, &rtpe_config.save_interface_ports, "Bind ports only on first available interface of desired family", NULL },
{ "subscribe-keyspace", 'k', 0, G_OPTION_ARG_STRING_ARRAY,&ks_a, "Subscription keyspace list", "INT INT ..."},
{ "listen-ng", 'n', 0, G_OPTION_ARG_STRING_ARRAY, &listenngs, "UDP ports to listen on, NG protocol","[IP46|HOSTNAME:]PORT ..." },
@ -703,8 +705,9 @@ static void options(int *argc, char ***argv) {
{ NULL, }
};
config_load(argc, argv, e, " - next-generation media proxy",
"/etc/rtpengine/rtpengine.conf", "rtpengine", &rtpe_config.common);
config_load_ext(argc, argv, e, " - next-generation media proxy",
"/etc/rtpengine/rtpengine.conf", "rtpengine", &rtpe_config.common,
&templates_section, templates);
// default values, if not configured
if (rtpe_config.rec_method == NULL)
@ -1120,6 +1123,9 @@ static void options(int *argc, char ***argv) {
if (rtpe_config.cpu_affinity <= 0)
die("Number of CPU cores is unknown, cannot auto-set socket CPU affinity");
}
// everything OK, do post-processing
}
static void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) {
@ -1276,7 +1282,7 @@ fallback:
}
static void init_everything(void) {
static void init_everything(GHashTable *templates) {
bufferpool_init();
gettimeofday(&rtpe_now, NULL);
log_init(rtpe_common_config_ptr->log_name);
@ -1299,7 +1305,7 @@ static void init_everything(void) {
interfaces_init(&rtpe_config.interfaces);
iptables_init();
control_ng_init();
if (call_interfaces_init())
if (call_interfaces_init(templates))
abort();
statistics_init();
#ifdef WITH_TRANSCODING
@ -1506,8 +1512,11 @@ static void uring_poller_loop(void *ptr) {
int main(int argc, char **argv) {
early_init();
options(&argc, &argv);
init_everything();
{
g_autoptr(GHashTable) templates = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
options(&argc, &argv, templates);
init_everything(templates);
}
create_everything();
fill_initial_rtpe_cfg(&initial_rtpe_config);

@ -582,6 +582,12 @@ Optionally included keys are:
Contains an integer corresponding to the SIP response code (e.g. 180 or
200) if this signalling message was triggered by a SIP response.
* `template`
Contains the name of a signalling template to be used for this particular
control message. See documentation for *SIGNALLING TEMPLATES* in the man
page.
* `via-branch`
The SIP `Via` branch as string. Used to additionally refine the matching logic between media streams

@ -151,6 +151,18 @@ at the command line. See the __\-\-config-file__ option below for details.
In this case, startup of the daemon will fail with an error if this option
is given.
- __\-\-templates=__*STR*
Name of the config file section to contain signalling templates. Requires a
configuration file to be in use (i.e. not __\-\-config-file=none__).
Default value is unset (i.e. no templates supported).
If set, then each entry within the given config section corresponds to a
named signalling template, which can then be used by referencing it via the
__template=...__ key in a signalling message to *rtpengine*.
See section *SIGNALLING TEMPLATES* below.
- __-S__, __\-\-save-interface-ports__
Will bind ports only on the first available local interface, of desired
@ -1522,6 +1534,48 @@ used by the __rtpproxy__ module, the interfaces must be named __internal__
and __external__ corresponding to the __i__ and __e__ flags if you wish to
use network bridging in this mode.
## SIGNALLING TEMPLATES
Since much of the behaviour of *rtpengine* is controlled by flags and
keys/values given to it during runtime as part of the signalling control
protocol that is used for communication between the controlling agent (e.g. a
SIP proxy) and the *rtpengine* process, there often is a need to repeatedly
give the same set of default flags and values to *rtpengine* for each message
sent to it. This can lead to controlling scripts that are hard to maintain or
hard to read. To alleviate this problem, *rtpengine* supports signalling
templates that can be configured in its main configuration file and can then be
referred to by short names.
To use this feature, a configuration file must be in use (by default
`/etc/rtpengine/rtpengine.conf`) and the configuration key __templates=...__
must be set to a non-empty string. The value gives the name of the section in
the configuration file to contain signalling templates. For example, if the
value is set to __templates=templates__, then the section __[templates]__ will
be used to read signalling templates.
Each key/value in this file section then corresponds to one signalling
template, and can be referred to via __template=...__ in any control message.
For example, in order to make an offer to a WebRTC-compliant client, a Kamailio
or OpenSIPS script may have used:
rtpengine_offer("transport-protocol=UDP/TLS/RTP/SAVPF ICE=force trickle-ICE rtcp-mux=[offer require] no-rtcp-attribute SDES=off generate-mid");
This entire string of flags can now be converted into a signalling template in
the config file as such:
[rtpengine]
...
templates = templates
...
[templates]
WebRTC = transport-protocol=UDP/TLS/RTP/SAVPF ICE=force trickle-ICE rtcp-mux=[offer require] no-rtcp-attribute SDES=off generate-mid
The __offer__ command in Kamailio or OpenSIPS can then simply be turned into:
rtpengine_offer("template=WebRTC");
## EXIT STATUS
- __0__

@ -14,6 +14,8 @@ table = 0
interface = any
# name of config section in this file to contain signalling templates
templates = templates
listen-ng = localhost:2223
@ -149,6 +151,10 @@ recording-method = proc
# socket-cpu-affinity = -1
# rtcp-interval = 5000
# signalling templates (see key `templates` above)
[templates]
WebRTC = transport-protocol=UDP/TLS/RTP/SAVPF ICE=force trickle-ICE rtcp-mux=[offer require] no-rtcp-attribute SDES=off generate-mid
[rtpengine-testing]
table = -1
interface = 10.15.20.121

@ -263,6 +263,7 @@ RTPE_NG_FLAGS_STR_CASE_HT_PARAMS
extern bool trust_address_def;
extern bool dtls_passive_def;
extern str_case_value_ht rtpe_signalling_templates;
str *call_request_tcp(char **);
str *call_lookup_tcp(char **);
@ -312,7 +313,7 @@ void call_unlock_release(call_t *c);
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(sdp_ng_flags, call_ng_free_flags)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(call_t, call_unlock_release)
int call_interfaces_init(void);
int call_interfaces_init(GHashTable *);
void call_interfaces_free(void);
void call_interfaces_timer(void);

@ -155,13 +155,31 @@ void config_load_free(struct rtpengine_common_config *cconfig) {
g_free(cconfig->pidfile);
}
static void load_templates(GKeyFile *kf, const char *template_section, GHashTable *templates) {
size_t length;
g_autoptr(GError) err = NULL;
g_autoptr(char_p) keys = g_key_file_get_keys(kf, template_section, &length, &err);
if (err)
die("Failed to load templates from given config file section '%s': %s", template_section, err->message);
if (!keys)
return; // empty config section
for (char **key = keys; *key; key++) {
char *val = g_key_file_get_string(kf, template_section, *key, &err);
if (err)
die("Failed to read template value '%s' from config file: %s", *key, err->message);
g_hash_table_insert(templates, g_strdup(*key), val); // hash table takes ownership of both
}
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionEntry, free)
typedef char *char_p_shallow;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(char_p_shallow, g_free)
void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char *description,
void config_load_ext(int *argc, char ***argv, GOptionEntry *app_entries, const char *description,
char *default_config, char *default_section,
struct rtpengine_common_config *cconfig)
struct rtpengine_common_config *cconfig,
char * const *template_section, GHashTable *templates)
{
g_autoptr(GOptionContext) c = NULL;
g_autoptr(GError) er = NULL;
@ -360,6 +378,9 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char
}
}
if (template_section && *template_section && templates)
load_templates(kf, *template_section, templates);
out:
// default common values, if not configured
if (rtpe_common_config_ptr->log_name == NULL)

@ -66,9 +66,16 @@ void resources(void);
void wpidfile(void);
void service_notify(const char *message);
void config_load_free(struct rtpengine_common_config *);
void config_load(int *argc, char ***argv, GOptionEntry *entries, const char *description,
void config_load_ext(int *argc, char ***argv, GOptionEntry *entries, const char *description,
char *default_config, char *default_section,
struct rtpengine_common_config *);
struct rtpengine_common_config *,
char * const *template_section, GHashTable *templates);
INLINE void config_load(int *argc, char ***argv, GOptionEntry *entries, const char *description,
char *default_config, char *default_section,
struct rtpengine_common_config *cc)
{
config_load_ext(argc, argv, entries, description, default_config, default_section, cc, NULL, NULL);
}
char *get_thread_buf(void);
int thread_create(void *(*func)(void *), void *arg, bool joinable, pthread_t *handle, const char *name);

@ -11,7 +11,7 @@ use NGCP::Rtpclient::ICE;
use POSIX;
autotest_start(qw(--config-file=test.conf)) or die;
autotest_start(qw(--config-file=test1.conf)) or die;
@ -69,6 +69,42 @@ a=rtcp:PORT
SDP
new_call;
offer('template', { template => 'WebRTC' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.19
t=0 0
m=audio 6000 RTP/AVP 0 8
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
t=0 0
m=audio PORT UDP/TLS/RTP/SAVPF 0 8
c=IN IP4 203.0.113.1
a=mid:1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp-mux
a=setup:actpass
a=fingerprint:sha-256 FINGERPRINT256
a=tls-id:TLS_ID
a=ice-ufrag:ICEUFRAG
a=ice-pwd:ICEPWD
a=ice-options:trickle
a=candidate:ICEBASE 1 UDP 2130706431 203.0.113.1 PORT typ host
a=candidate:ICEBASE 1 UDP 2130706175 203.0.113.2 PORT typ host
a=candidate:ICEBASE 1 UDP 2130705919 2001:db8:4321::1 PORT typ host
a=candidate:ICEBASE 1 UDP 2130705663 2001:db8:4321::2 PORT typ host
a=end-of-candidates
SDP
#done_testing;NGCP::Rtpengine::AutoTest::terminate('f00');exit;
done_testing();

@ -74,7 +74,7 @@ int main(void) {
rtpe_ssl_init();
call_init();
statistics_init();
call_interfaces_init();
call_interfaces_init(NULL);
ice_init();
control_ng_init();
dtls_init();

@ -5,3 +5,7 @@ listen-ng = 2223
foreground = true
log-level = 7
log-stderr = true
templates = templates
[templates]
WebRTC = transport-protocol=UDP/TLS/RTP/SAVPF ICE=force trickle-ICE rtcp-mux=[offer require] no-rtcp-attribute SDES=off generate-mid
Loading…
Cancel
Save