diff --git a/modules/siprec/doc/siprec_admin.xml b/modules/siprec/doc/siprec_admin.xml
index 409716e181f..dc5b249fa5c 100644
--- a/modules/siprec/doc/siprec_admin.xml
+++ b/modules/siprec/doc/siprec_admin.xml
@@ -273,8 +273,7 @@ modparam("siprec", "skip_failover_codes", "[34][0-9][0-9]")
Exported Functions
- siprec_start_recording(srs, [group], [caller],
- [callee], [rtpproxy_sock], [media_ip], [headers])
+ siprec_start_recording(srs[, rtpproxy_sock])
Calling this function on an initial
@@ -299,21 +298,6 @@ modparam("siprec", "skip_failover_codes", "[34][0-9][0-9]")
for more
information.
-
- group (string, optional) - an opaque values
- used by the SIPREC protocol to group calls in certain
- profiles.
-
-
- caller (string, optional) - an XML block
- containing information about the caller. If absent, the
- From header is used to build the value from.
-
-
- callee (string, optional) - an XML block
- containing information about the callee. If absent, the
- To header is used to build the value from.
-
rtpproxy_sock (string, optional) - the
RTPProxy socket used for this call. If absent, the rtpproxy
@@ -321,17 +305,6 @@ modparam("siprec", "skip_failover_codes", "[34][0-9][0-9]")
based on the default set provisioned in the
rtpproxy module.
-
- media_ip (string, optional) - the IP that
- RTPProxy will be streaming media from. If absent
- 127.0.0.1 will be used.
-
-
- headers (string, optional) - extra headers
- that are to be added in the initial request towards the SRS.
- NOTE: headers must be separated by
- \r\n and must end with \r\n.
-
@@ -437,5 +410,57 @@ modparam("siprec", "skip_failover_codes", "[34][0-9][0-9]")
+
+ Exported Pseudo-Variables
+
+ $siprec
+
+ Used to modify/describe different siprec sessions
+ parameters that should be taken into account by the
+ function.
+
+
+ The context of this variable is only limited to the current
+ message processed - it is not available at the transaction
+ or dialog level.
+
+
+ Any of this setting is optional.
+
+
+ Settings that can be provisioned:
+
+
+
+ group - an apaque value that will be inserted
+ in the SIPREC body and represents the name of the group that can be
+ used to clasify calls in certain profiles. If missing, no group is added.
+
+
+ caller - an XML block containing information
+ about the caller. If absent, the From header
+ is used to build the value.
+
+
+ callee - an XML block containing information
+ about the callee. If absent, the To header
+ is used to build the value.
+
+
+ media_ip - the IP that
+ RTPProxy will be streaming media from. If absent
+ 127.0.0.1 will be used.
+
+
+ headers - extra headers
+ that are to be added in the initial request towards the SRS.
+ NOTE: headers must be separated by
+ \r\n and must end with \r\n.
+
+
+
+
+
+
diff --git a/modules/siprec/siprec.c b/modules/siprec/siprec.c
index 7e5badf6555..6780dd74b4f 100644
--- a/modules/siprec/siprec.c
+++ b/modules/siprec/siprec.c
@@ -31,14 +31,14 @@
#include "siprec_sess.h"
#include "siprec_logic.h"
+#include "siprec_var.h"
static int mod_preinit(void);
static int mod_init(void);
static int child_init(int);
static void mod_destroy(void);
-static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group,
- str *_cA, str *_cB, str *rtp, str *m_ip, str *_hdrs);
+static int siprec_start_rec(struct sip_msg *msg, str *srs, str *rtp);
static int siprec_pause_rec(struct sip_msg *msg);
static int siprec_resume_rec(struct sip_msg *msg);
@@ -61,11 +61,6 @@ static dep_export_t deps = {
static cmd_export_t cmds[] = {
{"siprec_start_recording",(cmd_function)siprec_start_rec, {
{CMD_PARAM_STR,0,0},
- {CMD_PARAM_STR|CMD_PARAM_OPT,0,0},
- {CMD_PARAM_STR|CMD_PARAM_OPT,0,0},
- {CMD_PARAM_STR|CMD_PARAM_OPT,0,0},
- {CMD_PARAM_STR|CMD_PARAM_OPT,0,0},
- {CMD_PARAM_STR|CMD_PARAM_OPT,0,0},
{CMD_PARAM_STR|CMD_PARAM_OPT,0,0}, {0,0,0}},
REQUEST_ROUTE|ONREPLY_ROUTE},
{"siprec_pause_recording",(cmd_function)siprec_pause_rec,
@@ -83,6 +78,13 @@ static param_export_t params[] = {
{0, 0, 0}
};
+static pv_export_t vars[] = {
+ { {"siprec", sizeof("siprec")-1}, 1000,
+ pv_get_siprec, pv_set_siprec, pv_parse_siprec,
+ 0, 0, 0 },
+};
+
+
/* module exports */
struct module_exports exports = {
"siprec", /* module name */
@@ -96,7 +98,7 @@ struct module_exports exports = {
params, /* exported parameters */
0, /* exported statistics */
0, /* exported MI functions */
- 0, /* exported pseudo-variables */
+ vars, /* exported pseudo-variables */
0, /* extra processes */
0, /* extra transformations */
mod_preinit, /* module pre-initialization function */
@@ -134,6 +136,11 @@ static int mod_preinit(void)
srec_dlg_idx = srec_dlg.dlg_ctx_register_ptr(NULL);
+ if (init_srec_var() < 0) {
+ LM_ERR("cannot initialize siprec variable!\n");
+ return -1;
+ }
+
return 0;
}
@@ -188,13 +195,13 @@ static void tm_src_unref_session(void *p)
/*
* function that simply prints the parameters passed
*/
-static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group,
- str *_cA, str *_cB, str *rtp, str *m_ip, str *_hdrs)
+static int siprec_start_rec(struct sip_msg *msg, str *srs, str *rtp)
{
int ret;
str *aor, *display, *xml_val;
struct src_sess *ss;
struct dlg_cell *dlg;
+ struct srec_var *var;
/* create the dialog, if does not exist yet */
dlg = srec_dlg.get_dlg();
@@ -206,11 +213,17 @@ static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group,
dlg = srec_dlg.get_dlg();
}
+ var = get_srec_var();
+
/* XXX: if there is a forced send socket in the message, use it
* this is the only way to provide a different socket for SRS, but
* we might need to take a different approach */
/* check if the current dialog has a siprec session ongoing */
- if (!(ss = src_new_session(srs, rtp, m_ip, group, _hdrs, msg->force_send_socket))) {
+ if (!(ss = src_new_session(srs, rtp,
+ (var && var->media.len?&var->media:NULL),
+ (var && var->group.len?&var->group:NULL),
+ (var && var->headers.len?&var->headers:NULL),
+ msg->force_send_socket))) {
LM_ERR("cannot create siprec session!\n");
return -2;
}
@@ -224,8 +237,8 @@ static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group,
ret = -2;
/* caller info */
- if (_cA) {
- xml_val = _cA;
+ if (var && var->caller.len) {
+ xml_val = &var->caller;
display = aor = NULL;
} else {
if (parse_from_header(msg) < 0) {
@@ -246,8 +259,8 @@ static int siprec_start_rec(struct sip_msg *msg, str *srs, str *group,
goto session_cleanup;
}
/* caller info */
- if (_cB) {
- xml_val = _cB;
+ if (var && var->callee.len) {
+ xml_val = &var->callee;
} else {
if ((!msg->to && parse_headers(msg, HDR_TO_F, 0) < 0) || !msg->to) {
LM_ERR("inexisting or invalid to header!\n");
diff --git a/modules/siprec/siprec_var.c b/modules/siprec/siprec_var.c
new file mode 100644
index 00000000000..84475921228
--- /dev/null
+++ b/modules/siprec/siprec_var.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2021 OpenSIPS Project
+ *
+ * This file is part of opensips, a free SIP server.
+ *
+ * opensips 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.
+ *
+ * opensips is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "siprec_var.h"
+#include "../../ut.h"
+#include "../../context.h"
+
+#define SIPREC_VAR_INVAID_ID (-1)
+#define SIPREC_VAR_GROUP_ID (1 << 0)
+#define SIPREC_VAR_CALLER_ID (1 << 1)
+#define SIPREC_VAR_CALLEE_ID (1 << 2)
+#define SIPREC_VAR_HEADERS_ID (1 << 3)
+#define SIPREC_VAR_MEDIA_ID (1 << 4)
+
+struct {
+ const char *name;
+ const int id;
+} siprec_var_names[] = {
+ {"group", SIPREC_VAR_GROUP_ID},
+ {"caller", SIPREC_VAR_CALLER_ID},
+ {"callee", SIPREC_VAR_CALLEE_ID},
+ {"media_ip", SIPREC_VAR_MEDIA_ID},
+ {"headers", SIPREC_VAR_HEADERS_ID},
+};
+
+static int srec_msg_idx;
+
+#define SIPREC_GET_VAR() (struct srec_var *)\
+ (context_get_ptr(CONTEXT_GLOBAL, current_processing_ctx, srec_msg_idx))
+
+struct srec_var *get_srec_var(void)
+{
+ return SIPREC_GET_VAR();
+}
+
+static struct srec_var *get_srec_var_new(void)
+{
+ struct srec_var *var = SIPREC_GET_VAR();
+ if (var)
+ return var;
+ /* not found - create a new one */
+ var = pkg_malloc(sizeof *var);
+ if (!var) {
+ LM_ERR("oom for siprec var!\n");
+ return NULL;
+ }
+ memset(var, 0, sizeof *var);
+ context_put_ptr(CONTEXT_GLOBAL, current_processing_ctx, srec_msg_idx, var);
+ return var;
+}
+
+static void free_srec_var(void *v)
+{
+ struct srec_var *sv = (struct srec_var *)v;
+ if (sv->group.s)
+ pkg_free(sv->group.s);
+ if (sv->caller.s)
+ pkg_free(sv->caller.s);
+ if (sv->callee.s)
+ pkg_free(sv->callee.s);
+ if (sv->media.s)
+ pkg_free(sv->media.s);
+ if (sv->headers.s)
+ pkg_free(sv->headers.s);
+ pkg_free(sv);
+}
+
+
+static int pv_parse_siprec_name(const str *name)
+{
+ int s;
+ for (s = 0; s < (sizeof(siprec_var_names)/sizeof(siprec_var_names[0])); s++) {
+ if (str_match_nt(name, siprec_var_names[s].name))
+ return siprec_var_names[s].id;
+ }
+ LM_ERR("unknwon siprec variable %.*s\n", name->len, name->s);
+ return SIPREC_VAR_INVAID_ID;
+}
+
+static int pv_parse_siprec_get_name(struct sip_msg *msg, pv_param_t *p)
+{
+ pv_value_t tv;
+
+ if (p->pvn.type == PV_NAME_INTSTR)
+ return p->pvn.u.isname.type;
+
+ if(pv_get_spec_value(msg, (const pv_spec_p)(p->pvn.u.dname), &tv)!=0)
+ {
+ LM_ERR("cannot get siprec value\n");
+ return SIPREC_VAR_INVAID_ID;
+ }
+
+ if(tv.flags&PV_VAL_NULL || tv.flags&PV_VAL_EMPTY)
+ {
+ LM_ERR("null or empty name\n");
+ return -1;
+ }
+
+ if(!(tv.flags&PV_VAL_STR))
+ tv.rs.s = int2str(tv.ri, &tv.rs.len);
+
+ return pv_parse_siprec_name(&tv.rs);
+}
+
+
+int pv_parse_siprec(pv_spec_p sp, const str *in)
+{
+ char *p;
+ char *s;
+ pv_spec_p nsp = 0;
+
+ if(in==NULL || in->s==NULL || sp==NULL)
+ return -1;
+ p = in->s;
+ if(*p==PV_MARKER)
+ {
+ nsp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
+ if(nsp==NULL)
+ {
+ LM_ERR("no more memory\n");
+ return -1;
+ }
+ s = pv_parse_spec(in, nsp);
+ if(s==NULL)
+ {
+ LM_ERR("invalid name [%.*s]\n", in->len, in->s);
+ pv_spec_free(nsp);
+ return -1;
+ }
+ sp->pvp.pvn.type = PV_NAME_PVAR;
+ sp->pvp.pvn.u.dname = (void*)nsp;
+ return 0;
+ }
+ sp->pvp.pvn.type = PV_NAME_INTSTR;
+ sp->pvp.pvn.u.isname.type = pv_parse_siprec_name(in);
+ return (sp->pvp.pvn.u.isname.type == SIPREC_VAR_INVAID_ID)?-1:0;
+}
+
+int pv_get_siprec(struct sip_msg *msg, pv_param_t *param,
+ pv_value_t *val)
+{
+ str *field = NULL;
+ struct srec_var *sv = SIPREC_GET_VAR();
+ if (!sv)
+ return pv_get_null(msg, param, val);
+
+ switch (pv_parse_siprec_get_name(msg, param)) {
+ case SIPREC_VAR_GROUP_ID:
+ field = &sv->group;
+ break;
+ case SIPREC_VAR_CALLER_ID:
+ field = &sv->caller;
+ break;
+ case SIPREC_VAR_CALLEE_ID:
+ field = &sv->callee;
+ break;
+ case SIPREC_VAR_MEDIA_ID:
+ field = &sv->media;
+ break;
+ case SIPREC_VAR_HEADERS_ID:
+ field = &sv->headers;
+ break;
+ default:
+ LM_BUG("unknown field!\n");
+ case SIPREC_VAR_INVAID_ID:
+ return -1;
+ }
+ if (!field) {
+ LM_BUG("unknown field!\n");
+ return -1;
+ }
+
+ if (field->len < 0)
+ return pv_get_null(msg, param, val);
+
+ val->rs = *field;
+ val->flags = PV_VAL_STR;
+
+ return 0;
+}
+
+int pv_set_siprec(struct sip_msg* msg, pv_param_t *param,
+ int op, pv_value_t *val)
+{
+ int rc;
+ str *field = NULL, tmp;
+ struct srec_var *sv = get_srec_var_new();
+ if (!sv)
+ return -1;
+
+ switch (pv_parse_siprec_get_name(msg, param)) {
+ case SIPREC_VAR_GROUP_ID:
+ field = &sv->group;
+ break;
+ case SIPREC_VAR_CALLER_ID:
+ field = &sv->caller;
+ break;
+ case SIPREC_VAR_CALLEE_ID:
+ field = &sv->callee;
+ break;
+ case SIPREC_VAR_MEDIA_ID:
+ field = &sv->media;
+ break;
+ case SIPREC_VAR_HEADERS_ID:
+ field = &sv->headers;
+ break;
+ default:
+ LM_BUG("unknown field %d!\n", pv_parse_siprec_get_name(msg, param));
+ case SIPREC_VAR_INVAID_ID:
+ return -1;
+ }
+ if (!field) {
+ LM_BUG("unknown field!\n");
+ return -1;
+ }
+ if (!(val->flags & PV_VAL_STR)) {
+ tmp.s = int2str(val->ri, &tmp.len);
+ rc = pkg_str_dup(field, &tmp);
+ } else {
+ rc = pkg_str_dup(field, &val->rs);
+ }
+
+ return rc;
+}
+
+int init_srec_var(void)
+{
+ srec_msg_idx = context_register_ptr(CONTEXT_GLOBAL, free_srec_var);
+ return 0;
+}
diff --git a/modules/siprec/siprec_var.h b/modules/siprec/siprec_var.h
new file mode 100644
index 00000000000..bc29ff8ebf0
--- /dev/null
+++ b/modules/siprec/siprec_var.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 OpenSIPS Project
+ *
+ * This file is part of opensips, a free SIP server.
+ *
+ * opensips 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.
+ *
+ * opensips is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _SIPREC_VAR_H_
+#define _SIPREC_VAR_H_
+
+#include "../../str.h"
+#include "../../pvar.h"
+
+struct srec_var {
+ str group, caller, callee, media, headers;
+};
+
+int init_srec_var(void);
+int pv_parse_siprec(pv_spec_p sp, const str *in);
+int pv_get_siprec(struct sip_msg *msg, pv_param_t *param,
+ pv_value_t *val);
+int pv_set_siprec(struct sip_msg* msg, pv_param_t *param,
+ int op, pv_value_t *val);
+
+struct srec_var *get_srec_var(void);
+
+#endif /* _SIPREC_VAR_H_ */