Skip to content

Commit

Permalink
cfgutils: Add support for large diffs in ts_usec_delta()
Browse files Browse the repository at this point in the history
This patch reworks the 5th parameter as a string output variable, thus
avoiding issues related to integer overflows when the time diffs get
larger (e.g. differences of 35+ minutes, which are not uncommon).

Note: NOT backwards-compatible
  • Loading branch information
liviuchircu committed Apr 20, 2023
1 parent 422f815 commit 5fc57e9
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 18 deletions.
53 changes: 40 additions & 13 deletions modules/cfgutils/cfgutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ mi_response_t *mi_check_hash(const mi_params_t *params,
static int pv_get_random_val(struct sip_msg *msg, pv_param_t *param,
pv_value_t *res);

static int ts_usec_delta(struct sip_msg *msg, int *t1s,
int *t1u, int *t2s, int *t2u, pv_spec_t *_res);
static int ts_usec_delta(struct sip_msg *msg, int *t1s, int *t1u,
int *t2s, int *t2u, pv_spec_t *pv_delta_str, pv_spec_t *pv_delta_int);
int check_time_rec(struct sip_msg *_, char *time_rec, unsigned int *ptime);

#ifdef HAVE_TIMER_FD
Expand Down Expand Up @@ -182,7 +182,8 @@ static const cmd_export_t cmds[]={
{CMD_PARAM_INT, 0, 0},
{CMD_PARAM_INT, 0, 0},
{CMD_PARAM_INT, 0, 0},
{CMD_PARAM_VAR, fixup_check_pv_setf, 0}, {0,0,0}},
{CMD_PARAM_VAR|CMD_PARAM_OPT, fixup_check_pv_setf, 0},
{CMD_PARAM_VAR|CMD_PARAM_OPT, fixup_check_pv_setf, 0}, {0,0,0}},
REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE|
STARTUP_ROUTE|TIMER_ROUTE|EVENT_ROUTE},
{"get_static_lock",(cmd_function)get_static_lock, {
Expand Down Expand Up @@ -307,8 +308,8 @@ struct module_exports exports = {

static int fixup_check_pv_setf(void **param)
{
if (((pv_spec_t*)*param)->setf == 0) {
LM_ERR("invalid pvar\n");
if (!pv_is_w(((pv_spec_t*)*param))) {
LM_ERR("invalid pvar: must be writable\n");
return E_SCRIPT;
}

Expand Down Expand Up @@ -824,18 +825,44 @@ static int pv_sel_weight(struct sip_msg* msg, pv_spec_t *pv_name)
return -1;
}

static int ts_usec_delta(struct sip_msg *msg, int *t1s,
int *t1u, int *t2s, int *t2u, pv_spec_t *_res)
static int ts_usec_delta(struct sip_msg *msg, int *t1s, int *t1u,
int *t2s, int *t2u, pv_spec_t *pv_delta_str, pv_spec_t *pv_delta_int)
{
pv_value_t res;
pv_value_t val;
long long diff;

res.ri = abs(1000000 * (*t1s - *t2s) + *t1u - *t2u);
res.flags = PV_TYPE_INT;
diff = llabs(1000000LL * (*t1s - *t2s) + *t1u - *t2u);

if (pv_set_value(msg, _res, 0, &res)) {
LM_ERR("cannot store result value\n");
return -1;
if (pv_delta_str) {
char diff_buf[20 + 1];

val.rs.s = diff_buf;
val.rs.len = sprintf(diff_buf, "%lld", diff);
val.flags = PV_VAL_STR;

if (pv_set_value(msg, pv_delta_str, 0, &val) != 0) {
LM_ERR("failed to set the 'delta_str' output variable\n");
return -1;
}
}

if (pv_delta_int) {
if (diff > INT_MAX) {
LM_ERR("diff is too large to store in 'delta_int' (%lld us), "
"use the 'delta_str' output variable instead!\n", diff);
return -1;
}

val.rs = STR_NULL;
val.ri = (int)diff;
val.flags = PV_VAL_INT|PV_TYPE_INT;

if (pv_set_value(msg, pv_delta_int, 0, &val)) {
LM_ERR("failed to set the 'delta_int' output variable\n");
return -1;
}
}

return 1;
}

Expand Down
16 changes: 11 additions & 5 deletions modules/cfgutils/doc/cfgutils_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -473,12 +473,18 @@ $var(next_gw_idx) = set_select_weight($avp(gw_success_rates));
</section>
<section id="func_ts_usec_delta" xreflabel="ts_usec_delta()">
<title>
<function moreinfo="none">ts_usec_delta(t1_sec, t1_usec, t2_sec, t2_usec, delta)</function>
<function moreinfo="none">ts_usec_delta(t1_sec, t1_usec, t2_sec, t2_usec, [delta_str], [delta_int])</function>
</title>
<para>
This function returns the difference between two timestamps, specified
in seconds and microseconds. The result is returned in the last
parameter, expressed in microseconds.
This function returns the absolute difference between the two given
timestamps. The result is expressed as <emphasis>microseconds</emphasis>
and can be returned as either string or integer.
</para>
<para>
<emphasis role='bold'>WARNING:</emphasis> when using
<emphasis>delta_int</emphasis>, the function will return error code
<emphasis role='bold'>-1</emphasis> in case the difference overflows
the signed integer holder! (i.e. a diff of ~35 minutes or more)
</para>
<para>
This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
Expand All @@ -488,7 +494,7 @@ $var(next_gw_idx) = set_select_weight($avp(gw_success_rates));
<title><function>ts_usec_delta</function> usage</title>
<programlisting format="linespecific">
...
ts_usec_delta($var(t1s), 300, 10, $var(t2ms), $var(result));
ts_usec_delta($var(t1s), 300, 10, $var(t2us), $var(diff_str));
...
</programlisting>
</example>
Expand Down

0 comments on commit 5fc57e9

Please sign in to comment.