From: Liviu Chircu <liviu@opensips.org>
Date: Fri, 12 Feb 2016 17:12:57 +0200
Subject: [PATCH] Improve qvalue parsing
* accept qvalues with no decimal digits (e.g. "1." and "0.")
(this removes E_Q_DEC_MISSING from error.h)
* improve bad qvalue error reporting
(cherry picked from commit ed60363d9d66bf230872c535e3fc0cf7f117b2c7)
Conflicts:
cfg.y
diff --git a/cfg.y b/cfg.y
index b969ce0..8b67517 100644
--- a/cfg.y
+++ b/cfg.y
@@ -132,7 +132,7 @@ extern int yylex();
static void yyerror(char* s);
static void yyerrorf(char* fmt, ...);
static char* tmp;
-static int i_tmp;
+static int i_tmp, rc;
static void* cmd_tmp;
static struct socket_id* lst_tmp;
static int rt; /* Type of route block for find_export */
@@ -2751,13 +2751,18 @@ cmd: FORWARD LPAREN STRING RPAREN { mk_action2( $$, FORWARD_T,
| STRIP error { $$=0; yyerror("missing '(' or ')' ?"); }
| STRIP LPAREN error RPAREN { $$=0; yyerror("bad argument, "
"number expected"); }
- | APPEND_BRANCH LPAREN STRING COMMA STRING RPAREN {
- { qvalue_t q;
- if (str2q(&q, $5, strlen($5)) < 0) {
- yyerror("bad argument, q value expected");
- }
+ | APPEND_BRANCH LPAREN STRING COMMA STRING RPAREN {
+ {
+ qvalue_t q;
+
+ rc = str2q(&q, $5, strlen($5));
+ if (rc < 0)
+ yyerrorf("bad qvalue (%.*s): %s",
+ strlen($5), $5, qverr2str(rc));
+
mk_action2( $$, APPEND_BRANCH_T, STR_ST, NUMBER_ST, $3,
- (void *)(long)q); }
+ (void *)(long)q);
+ }
}
| APPEND_BRANCH LPAREN STRING RPAREN { mk_action2( $$, APPEND_BRANCH_T,
STR_ST, NUMBER_ST, $3, (void *)Q_UNSPECIFIED) ; }
diff --git a/error.c b/error.c
index 9042be3..715863b 100644
--- a/error.c
+++ b/error.c
@@ -105,10 +105,6 @@ int err2reason_phrase(
error_txt="q parameter too big";
*sip_error=-E_BAD_REQ;
break;
- case E_Q_DEC_MISSING:
- error_txt="Decimal part missing in q";
- *sip_error=-E_BAD_REQ;
- break;
case E_NO_DESTINATION:
error_txt="No destination available";
*sip_error=-E_BAD_SERVER;
diff --git a/error.h b/error.h
index 87854ca..8e6f6a9 100644
--- a/error.h
+++ b/error.h
@@ -46,8 +46,7 @@
#define E_Q_INV_CHAR -15 /*!< Invalid character in q */
#define E_Q_EMPTY -16 /*!< Empty q */
#define E_Q_TOO_BIG -17 /*!< q too big (> 1) */
-#define E_Q_DEC_MISSING -18 /*!< Decimal part missing */
-#define E_NO_DESTINATION -19 /*!< No available destination */
+#define E_NO_DESTINATION -18 /*!< No available destination */
/* opensips specific error codes */
#define E_IP_BLOCKED -473 /*!< destination filtered */
diff --git a/modules/registrar/sip_msg.c b/modules/registrar/sip_msg.c
index 28ad6bb..e5d895d 100644
--- a/modules/registrar/sip_msg.c
+++ b/modules/registrar/sip_msg.c
@@ -281,12 +281,16 @@ void calc_contact_expires(struct sip_msg* _m, param_t* _ep, int* _e, struct save
*/
int calc_contact_q(param_t* _q, qvalue_t* _r)
{
+ int rc;
+
if (!_q || (_q->body.len == 0)) {
*_r = default_q;
} else {
- if (str2q(_r, _q->body.s, _q->body.len) < 0) {
+ rc = str2q(_r, _q->body.s, _q->body.len);
+ if (rc < 0) {
rerrno = R_INV_Q; /* Invalid q parameter */
- LM_ERR("invalid q parameter\n");
+ LM_ERR("invalid qvalue (%.*s): %s\n",
+ _q->body.len, _q->body.s, qverr2str(rc));
return -1;
}
}
diff --git a/modules/uac_redirect/rd_funcs.c b/modules/uac_redirect/rd_funcs.c
index ef6a923..329f2cb 100644
--- a/modules/uac_redirect/rd_funcs.c
+++ b/modules/uac_redirect/rd_funcs.c
@@ -106,7 +106,7 @@ static void sort_contacts(contact_t *ct_list, str *ct_array,
{
param_t *q_para;
qvalue_t q;
- int i,j;
+ int i, j, rc;
char backup;
for( ; ct_list ; ct_list = ct_list->next ) {
@@ -123,8 +123,10 @@ static void sort_contacts(contact_t *ct_list, str *ct_array,
if (q_para==0 || q_para->body.len==0) {
q = DEFAULT_Q_VALUE;
} else {
- if (str2q( &q, q_para->body.s, q_para->body.len)!=0) {
- LM_ERR("invalid q param\n");
+ rc = str2q( &q, q_para->body.s, q_para->body.len);
+ if (rc != 0) {
+ LM_ERR("invalid qvalue (%.*s): %s\n",
+ q_para->body.len, q_para->body.s, qverr2str(rc));
/* skip this contact */
continue;
}
diff --git a/qvalue.c b/qvalue.c
index 5cd2cd9..34029f3 100644
--- a/qvalue.c
+++ b/qvalue.c
@@ -75,6 +75,7 @@ int str2q(qvalue_t* q, char* s, int len)
break;
case '.':
+ *q = 0;
state = ST_0_PT;
break;
@@ -167,15 +168,8 @@ int str2q(qvalue_t* q, char* s, int len)
}
}
- switch(state) {
- case ST_START:
+ if (state == ST_START)
return E_Q_EMPTY;
- case ST_0_PT:
- case ST_1_PT:
- return E_Q_DEC_MISSING;
-
- default:
- return 0;
- }
+ return 0;
}
diff --git a/qvalue.h b/qvalue.h
index 96aa81f..717844c 100644
--- a/qvalue.h
+++ b/qvalue.h
@@ -76,6 +76,10 @@ typedef int qvalue_t;
#define Q_PREFIX "0."
#define Q_PREFIX_LEN (sizeof(Q_PREFIX) - 1)
+#define qverr2str(rc) \
+ (rc == E_Q_INV_CHAR ? "bad characters" : \
+ rc == E_Q_EMPTY ? "empty value" : \
+ rc == E_Q_TOO_BIG ? "max value is 1.0" : "bad qvalue")
/*! \brief