$prefix.name - it MUST be only one AVP with that name to match binary
operators or on the right side of assignment
$prefix.name[] - allowed on both sides of assignment
on left side means - enable more AVPS with the same name
on the right side - all AVPs with the name are added (correctly ordered)
$prefix.name[index] - allowed on right side of assignment and as binary
operand, corresponds to value of index-th AVP in the list (if such exists)
1 means the AVP, which was added FIRST to the list (this unfortunatelly
means, that the AVP name is scanned through the whole list)
-1 means the AVP, which was added LAST to the list
prefix is one of following
f - FROM USER
t - TO USER
fd- FROM DOMAIN
td- TO DOMAIN
g - GLOBAL
and if ommited, the default FROM USER is used
=new function parse_avp_name, needs to be enhanced (does not accept
whitespace as the script parser does)
=new function search_avp_by_index, usable even for variant without the
brackets (then it checks the name exclusivity)
=xlog module uses new avp parse and search_by_index function
format string is %avp_syntax, e.g. %$MyAVP[1]
=avp module merged functions from another branch, not updated to new AVP
syntax fully
=script parser updated to new syntax
... | ... |
@@ -1,3 +1,4 @@ |
1 |
+ |
|
1 | 2 |
/* |
2 | 3 |
* $Id$ |
3 | 4 |
* |
... | ... |
@@ -714,6 +715,12 @@ int do_action(struct action* a, struct sip_msg* msg) |
714 | 715 |
|
715 | 716 |
case ADD_T: |
716 | 717 |
case ASSIGN_T: |
718 |
+ |
|
719 |
+ /* If the left attr was specified withou indexing brackets delete |
|
720 |
+ * existing AVPs before adding new ones |
|
721 |
+ */ |
|
722 |
+ if ((a->p1.attr->type & AVP_INDEX_ALL) != AVP_INDEX_ALL) delete_avp(a->p1.attr->type, a->p1.attr->name); |
|
723 |
+ |
|
717 | 724 |
if (a->p2_type == STRING_ST) { |
718 | 725 |
value.s = a->p2.str; |
719 | 726 |
flags = a->p1.attr->type | AVP_VAL_STR; |
... | ... |
@@ -750,27 +757,45 @@ int do_action(struct action* a, struct sip_msg* msg) |
750 | 757 |
} else if (a->p2_type == AVP_ST) { |
751 | 758 |
struct search_state st; |
752 | 759 |
avp_t* avp; |
760 |
+ avp_t* avp_mark; |
|
753 | 761 |
|
754 |
- /* If the action is assign then remove the old avp value before adding |
|
755 |
- * new ones |
|
756 |
- */ |
|
757 |
- if ((unsigned char)a->type == ASSIGN_T) delete_avp(a->p1.attr->type, a->p1.attr->name); |
|
758 |
- |
|
759 |
- avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st); |
|
760 |
- while(avp) { |
|
761 |
- /* We take only the type of value and name from the source avp |
|
762 |
- * and reset class and track flags |
|
763 |
- */ |
|
764 |
- flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL)); |
|
765 |
- if (add_avp(flags, name, value) < 0) { |
|
766 |
- LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n"); |
|
767 |
- ret=E_UNSPEC; |
|
762 |
+ avp_mark = NULL; |
|
763 |
+ if ((a->p2.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL) { |
|
764 |
+ avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st); |
|
765 |
+ while(avp) { |
|
766 |
+ /* We take only the type of value and name from the source avp |
|
767 |
+ * and reset class and track flags |
|
768 |
+ */ |
|
769 |
+ flags = (a->p1.attr->type & ~AVP_INDEX_ALL) | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL)); |
|
770 |
+ |
|
771 |
+ if (add_avp_before(avp_mark, flags, a->p1.attr->name, value) < 0) { |
|
772 |
+ LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n"); |
|
773 |
+ ret=E_UNSPEC; |
|
774 |
+ break; |
|
775 |
+ } |
|
776 |
+ |
|
777 |
+ /* move the mark, so the next found AVP will come before the one currently added |
|
778 |
+ * so they will have the same order as in the source list |
|
779 |
+ */ |
|
780 |
+ if (avp_mark) { |
|
781 |
+ avp_mark=avp_mark->next; |
|
782 |
+ } else { |
|
783 |
+ avp_mark=search_first_avp(flags, a->p1.attr->name, NULL, NULL); |
|
784 |
+ } |
|
785 |
+ |
|
786 |
+ avp = search_next_avp(&st, &value); |
|
787 |
+ } |
|
788 |
+ ret = 1; |
|
789 |
+ break; |
|
790 |
+ } else { |
|
791 |
+ avp = search_avp_by_index(a->p2.attr->type, a->p2.attr->name, &value, a->p2.attr->index); |
|
792 |
+ if (avp) { |
|
793 |
+ flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL)); |
|
794 |
+ } else { |
|
795 |
+ ret = E_UNSPEC; |
|
768 | 796 |
break; |
769 | 797 |
} |
770 |
- avp = search_next_avp(&st, &value); |
|
771 | 798 |
} |
772 |
- ret = 1; |
|
773 |
- break; |
|
774 | 799 |
} else if (a->p2_type == SELECT_ST) { |
775 | 800 |
int r; |
776 | 801 |
r = run_select(&value.s, a->p2.select, msg); |
... | ... |
@@ -793,8 +818,8 @@ int do_action(struct action* a, struct sip_msg* msg) |
793 | 818 |
|
794 | 819 |
/* If the action is assign then remove the old avp value |
795 | 820 |
* before adding new ones */ |
796 |
- if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name); |
|
797 |
- if (add_avp(flags, name, value) < 0) { |
|
821 |
+// if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name); |
|
822 |
+ if (add_avp(flags & ~AVP_INDEX_ALL, name, value) < 0) { |
|
798 | 823 |
LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n"); |
799 | 824 |
ret=E_UNSPEC; |
800 | 825 |
break; |
... | ... |
@@ -510,6 +510,10 @@ EAT_ABLE [\ \t\b\r] |
510 | 510 |
<ATTR>{ATTR_TODOMAIN} { count(); return ATTR_TODOMAIN; } |
511 | 511 |
<ATTR>{ATTR_GLOBAL} { count(); return ATTR_GLOBAL; } |
512 | 512 |
<ATTR>{DOT} { count(); return DOT; } |
513 |
+<ATTR>{LBRACK} { count(); return LBRACK; } |
|
514 |
+<ATTR>{RBRACK} { count(); return RBRACK; } |
|
515 |
+<ATTR>{STAR} { count(); return STAR; } |
|
516 |
+<ATTR>{DECNUMBER} { count(); yylval.intval=atoi(yytext);return NUMBER; } |
|
513 | 517 |
<ATTR>{ID} { count(); addstr(&s_buf, yytext, yyleng); |
514 | 518 |
yylval.strval=s_buf.s; |
515 | 519 |
memset(&s_buf, 0, sizeof(s_buf)); |
... | ... |
@@ -67,6 +67,7 @@ |
67 | 67 |
* 2005-12-11 added onsend_route support, fcmd (filtered cmd), |
68 | 68 |
* snd_{ip,port,proto,af}, to_{ip,proto} (andrei) |
69 | 69 |
* 2005-12-19 select framework (mma) |
70 |
+ * 2006-01-06 AVP index support (mma) |
|
70 | 71 |
* |
71 | 72 |
*/ |
72 | 73 |
|
... | ... |
@@ -336,6 +337,11 @@ static struct socket_id* mk_listen_id(char*, int, int); |
336 | 337 |
%type <strval> host_sep |
337 | 338 |
%type <intval> uri_type |
338 | 339 |
%type <attr> attr_id |
340 |
+%type <attr> attr_id_num_idx |
|
341 |
+%type <attr> attr_id_no_idx |
|
342 |
+%type <attr> attr_id_ass |
|
343 |
+%type <attr> attr_id_val |
|
344 |
+%type <attr> attr_id_any |
|
339 | 345 |
//%type <intval> class_id |
340 | 346 |
%type <intval> assign_op |
341 | 347 |
%type <select> select_id |
... | ... |
@@ -957,7 +963,7 @@ uri_type: URI {$$=URI_O;} |
957 | 963 |
; |
958 | 964 |
|
959 | 965 |
exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
960 |
- | METHOD strop attr_id {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); } |
|
966 |
+ | METHOD strop attr_id_val {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); } |
|
961 | 967 |
| METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); } |
962 | 968 |
| METHOD strop ID {$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); } |
963 | 969 |
| METHOD strop error { $$=0; yyerror("string expected"); } |
... | ... |
@@ -966,7 +972,7 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
966 | 972 |
} |
967 | 973 |
| uri_type strop STRING {$$ = mk_elem($2, $1, 0, STRING_ST, $3); } |
968 | 974 |
| uri_type strop host {$$ = mk_elem($2, $1, 0, STRING_ST, $3); } |
969 |
- | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); } |
|
975 |
+ | uri_type strop attr_id_val {$$ = mk_elem($2, $1, 0, AVP_ST, $3); } |
|
970 | 976 |
| uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); } |
971 | 977 |
| uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); } |
972 | 978 |
| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); } |
... | ... |
@@ -974,19 +980,19 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
974 | 980 |
" == , != or =~ expected"); |
975 | 981 |
} |
976 | 982 |
| SRCPORT intop NUMBER { $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); } |
977 |
- | SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); } |
|
983 |
+ | SRCPORT intop attr_id_val { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); } |
|
978 | 984 |
| SRCPORT intop error { $$=0; yyerror("number expected"); } |
979 | 985 |
| SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <= expected"); } |
980 | 986 |
|
981 | 987 |
| DSTPORT intop NUMBER { $$=mk_elem($2, DSTPORT_O, 0, NUMBER_ST, (void*)$3 ); } |
982 |
- | DSTPORT intop attr_id { $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); } |
|
988 |
+ | DSTPORT intop attr_id_val { $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); } |
|
983 | 989 |
| DSTPORT intop error { $$=0; yyerror("number expected"); } |
984 | 990 |
| DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <= expected"); } |
985 | 991 |
|
986 | 992 |
| SNDPORT intop NUMBER { onsend_check("snd_port"); |
987 | 993 |
$$=mk_elem($2, SNDPORT_O, 0, NUMBER_ST, |
988 | 994 |
(void*)$3 ); } |
989 |
- | SNDPORT intop attr_id { onsend_check("snd_port"); |
|
995 |
+ | SNDPORT intop attr_id_val { onsend_check("snd_port"); |
|
990 | 996 |
$$=mk_elem($2, SNDPORT_O, 0, AVP_ST, |
991 | 997 |
(void*)$3 ); } |
992 | 998 |
| SNDPORT intop error { $$=0; yyerror("number expected"); } |
... | ... |
@@ -995,14 +1001,14 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
995 | 1001 |
| TOPORT intop NUMBER { onsend_check("to_port"); |
996 | 1002 |
$$=mk_elem($2, TOPORT_O, 0, NUMBER_ST, |
997 | 1003 |
(void*)$3 ); } |
998 |
- | TOPORT intop attr_id { onsend_check("to_port"); |
|
1004 |
+ | TOPORT intop attr_id_val { onsend_check("to_port"); |
|
999 | 1005 |
$$=mk_elem($2, TOPORT_O, 0, AVP_ST, |
1000 | 1006 |
(void*)$3 ); } |
1001 | 1007 |
| TOPORT intop error { $$=0; yyerror("number expected"); } |
1002 | 1008 |
| TOPORT error { $$=0; yyerror("==, !=, <,>, >= or <= expected"); } |
1003 | 1009 |
|
1004 | 1010 |
| PROTO intop proto { $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); } |
1005 |
- | PROTO intop attr_id { $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); } |
|
1011 |
+ | PROTO intop attr_id_val { $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); } |
|
1006 | 1012 |
| PROTO intop error { $$=0; |
1007 | 1013 |
yyerror("protocol expected (udp, tcp or tls)"); |
1008 | 1014 |
} |
... | ... |
@@ -1011,7 +1017,7 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
1011 | 1017 |
| SNDPROTO intop proto { onsend_check("snd_proto"); |
1012 | 1018 |
$$=mk_elem($2, SNDPROTO_O, 0, NUMBER_ST, |
1013 | 1019 |
(void*)$3 ); } |
1014 |
- | SNDPROTO intop attr_id { onsend_check("snd_proto"); |
|
1020 |
+ | SNDPROTO intop attr_id_val { onsend_check("snd_proto"); |
|
1015 | 1021 |
$$=mk_elem($2, SNDPROTO_O, 0, AVP_ST, |
1016 | 1022 |
(void*)$3 ); } |
1017 | 1023 |
| SNDPROTO intop error { $$=0; |
... | ... |
@@ -1020,28 +1026,28 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
1020 | 1026 |
| SNDPROTO error { $$=0; yyerror("equal/!= operator expected"); } |
1021 | 1027 |
|
1022 | 1028 |
| AF intop NUMBER { $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); } |
1023 |
- | AF intop attr_id { $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); } |
|
1029 |
+ | AF intop attr_id_val { $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); } |
|
1024 | 1030 |
| AF intop error { $$=0; yyerror("number expected"); } |
1025 | 1031 |
| AF error { $$=0; yyerror("equal/!= operator expected"); } |
1026 | 1032 |
|
1027 | 1033 |
| SNDAF intop NUMBER { onsend_check("snd_af"); |
1028 | 1034 |
$$=mk_elem($2, SNDAF_O, 0, NUMBER_ST, |
1029 | 1035 |
(void *) $3 ); } |
1030 |
- | SNDAF intop attr_id { onsend_check("snd_af"); |
|
1036 |
+ | SNDAF intop attr_id_val { onsend_check("snd_af"); |
|
1031 | 1037 |
$$=mk_elem($2, SNDAF_O, 0, AVP_ST, |
1032 | 1038 |
(void *) $3 ); } |
1033 | 1039 |
| SNDAF intop error { $$=0; yyerror("number expected"); } |
1034 | 1040 |
| SNDAF error { $$=0; yyerror("equal/!= operator expected"); } |
1035 | 1041 |
|
1036 | 1042 |
| MSGLEN intop NUMBER { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); } |
1037 |
- | MSGLEN intop attr_id { $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); } |
|
1043 |
+ | MSGLEN intop attr_id_val { $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); } |
|
1038 | 1044 |
| MSGLEN intop MAX_LEN { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); } |
1039 | 1045 |
| MSGLEN intop error { $$=0; yyerror("number expected"); } |
1040 | 1046 |
| MSGLEN error { $$=0; yyerror("equal/!= operator expected"); } |
1041 | 1047 |
|
1042 | 1048 |
| RETCODE intop NUMBER { $$=mk_elem($2, RETCODE_O, 0, |
1043 | 1049 |
NUMBER_ST, (void *) $3 ); } |
1044 |
- | RETCODE intop attr_id { $$=mk_elem($2, RETCODE_O, 0, |
|
1050 |
+ | RETCODE intop attr_id_val { $$=mk_elem($2, RETCODE_O, 0, |
|
1045 | 1051 |
AVP_ST, (void *) $3 ); } |
1046 | 1052 |
| RETCODE intop error { $$=0; yyerror("number expected"); } |
1047 | 1053 |
| RETCODE error { $$=0; yyerror("equal/!= operator expected"); } |
... | ... |
@@ -1172,16 +1178,16 @@ exp_elem: METHOD strop STRING {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);} |
1172 | 1178 |
| exp_stm { $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1); } |
1173 | 1179 |
| NUMBER {$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); } |
1174 | 1180 |
|
1175 |
- | attr_id {$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); } |
|
1176 |
- | attr_id strop STRING {$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); } |
|
1177 |
- | attr_id strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); } |
|
1178 |
- | attr_id intop NUMBER {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); } |
|
1179 |
- | attr_id binop NUMBER {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); } |
|
1180 |
- | attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); } |
|
1181 |
+ | attr_id_val {$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); } |
|
1182 |
+ | attr_id_val strop STRING {$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); } |
|
1183 |
+ | attr_id_val strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); } |
|
1184 |
+ | attr_id_val intop NUMBER {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); } |
|
1185 |
+ | attr_id_val binop NUMBER {$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); } |
|
1186 |
+ | attr_id_val strop attr_id_val {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); } |
|
1181 | 1187 |
|
1182 | 1188 |
| select_id { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); } |
1183 | 1189 |
| select_id strop STRING { $$=mk_elem( $2, SELECT_O, $1, STRING_ST, $3); } |
1184 |
- | select_id strop attr_id { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); } |
|
1190 |
+ | select_id strop attr_id_val { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); } |
|
1185 | 1191 |
| select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); } |
1186 | 1192 |
; |
1187 | 1193 |
|
... | ... |
@@ -1334,67 +1340,62 @@ select_id : SELECT_MARK { sel.n = 0; sel.f = 0; } select_params { |
1334 | 1340 |
} |
1335 | 1341 |
; |
1336 | 1342 |
|
1343 |
+attr_class_spec: ATTR_FROMUSER { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_USER; } |
|
1344 |
+ |ATTR_TOUSER { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_USER; } |
|
1345 |
+ |ATTR_FROMDOMAIN { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_DOMAIN; } |
|
1346 |
+ |ATTR_TODOMAIN { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_DOMAIN; } |
|
1347 |
+ |ATTR_GLOBAL { s_attr->type |= AVP_TRACK_ALL | AVP_CLASS_GLOBAL; } |
|
1337 | 1348 |
|
1338 |
-attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1339 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1340 |
- s_attr->type = AVP_NAME_STR; |
|
1341 |
- s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); |
|
1342 |
- $$ = s_attr; |
|
1343 |
- } |
|
1344 |
-// | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1345 |
-// if (!s_attr) { yyerror("No memory left"); } |
|
1346 |
-// s_attr->type = AVP_NAME_STR | $2; |
|
1347 |
-// s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1348 |
-// $$ = s_attr; |
|
1349 |
-// } |
|
1350 |
- | ATTR_MARK ATTR_FROMUSER DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1351 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1352 |
- s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | AVP_CLASS_USER; |
|
1353 |
- s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1354 |
- $$ = s_attr; |
|
1355 |
- } |
|
1356 |
- | ATTR_MARK ATTR_TOUSER DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1357 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1358 |
- s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | AVP_CLASS_USER; |
|
1359 |
- s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1360 |
- $$ = s_attr; |
|
1361 |
- } |
|
1362 |
- | ATTR_MARK ATTR_FROMDOMAIN DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1363 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1364 |
- s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | AVP_CLASS_DOMAIN; |
|
1365 |
- s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1366 |
- $$ = s_attr; |
|
1367 |
- } |
|
1368 |
- | ATTR_MARK ATTR_TODOMAIN DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1369 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1370 |
- s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | AVP_CLASS_DOMAIN; |
|
1371 |
- s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1372 |
- $$ = s_attr; |
|
1373 |
- } |
|
1374 |
- | ATTR_MARK ATTR_GLOBAL DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1375 |
- if (!s_attr) { yyerror("No memory left"); } |
|
1376 |
- s_attr->type = AVP_NAME_STR | AVP_CLASS_GLOBAL; |
|
1377 |
- s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); |
|
1378 |
- $$ = s_attr; |
|
1379 |
- } |
|
1380 |
-// | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1381 |
-// if (!s_attr) { yyerror("No memory left"); } |
|
1382 |
-// s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3; |
|
1383 |
-// s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5); |
|
1384 |
-// $$ = s_attr; |
|
1385 |
-// } |
|
1349 |
+attr_name_spec : ID { s_attr->type |= AVP_NAME_STR; s_attr->name.s.s = $1; s_attr->name.s.len = strlen ($1); } |
|
1350 |
+; |
|
1351 |
+ |
|
1352 |
+attr_spec : attr_name_spec | |
|
1353 |
+ attr_class_spec DOT attr_name_spec |
|
1354 |
+; |
|
1355 |
+ |
|
1356 |
+attr_mark : ATTR_MARK |
|
1357 |
+ { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec)); |
|
1358 |
+ if (!s_attr) { yyerror("No memory left"); } |
|
1359 |
+ s_attr->type = 0; |
|
1360 |
+ } |
|
1361 |
+; |
|
1362 |
+ |
|
1363 |
+attr_id : attr_mark attr_spec { $$ = s_attr; } |
|
1364 |
+; |
|
1365 |
+ |
|
1366 |
+attr_id_num_idx : attr_mark attr_spec LBRACK NUMBER RBRACK |
|
1367 |
+ { s_attr->type|= (AVP_NAME_STR | ($4<0?AVP_INDEX_BACKWARD:AVP_INDEX_FORWARD)); |
|
1368 |
+ s_attr->index = ($4<0?-$4:$4); |
|
1369 |
+ $$ = s_attr; |
|
1370 |
+ } |
|
1371 |
+; |
|
1372 |
+ |
|
1373 |
+attr_id_no_idx : attr_mark attr_spec LBRACK RBRACK |
|
1374 |
+ { s_attr->type|= AVP_INDEX_ALL; |
|
1375 |
+ $$ = s_attr; |
|
1376 |
+ } |
|
1377 |
+; |
|
1378 |
+ |
|
1379 |
+attr_id_ass : attr_id | attr_id_no_idx |
|
1380 |
+; |
|
1381 |
+ |
|
1382 |
+attr_id_val : attr_id | attr_id_num_idx |
|
1383 |
+; |
|
1384 |
+ |
|
1385 |
+attr_id_any : attr_id | attr_id_no_idx | attr_id_num_idx |
|
1386 | 1386 |
; |
1387 | 1387 |
|
1388 |
-assign_op : ADDEQ { $$ = ADD_T; } |
|
1389 |
- | EQUAL { $$ = ASSIGN_T; } |
|
1388 |
+//assign_op : ADDEQ { $$ = ADD_T; } |
|
1389 |
+// | EQUAL { $$ = ASSIGN_T; } |
|
1390 |
+assign_op : EQUAL { $$ = ASSIGN_T; } |
|
1390 | 1391 |
; |
1391 | 1392 |
|
1392 |
-assign_action: attr_id assign_op STRING { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); } |
|
1393 |
- | attr_id assign_op NUMBER { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); } |
|
1394 |
- | attr_id assign_op fcmd { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); } |
|
1395 |
- | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); } |
|
1396 |
- | attr_id assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); } |
|
1397 |
- | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); } |
|
1393 |
+assign_action: attr_id_ass assign_op STRING { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); } |
|
1394 |
+ | attr_id_ass assign_op NUMBER { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); } |
|
1395 |
+ | attr_id_ass assign_op fcmd { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); } |
|
1396 |
+ | attr_id_ass assign_op attr_id_any { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); } |
|
1397 |
+ | attr_id_ass assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); } |
|
1398 |
+ | attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); } |
|
1398 | 1399 |
; |
1399 | 1400 |
|
1400 | 1401 |
cmd: FORWARD LPAREN host RPAREN { $$=mk_action( FORWARD_T, |
... | ... |
@@ -198,6 +198,7 @@ int parse_tw_append( modparam_t type, void* val) |
198 | 198 |
char bar; |
199 | 199 |
str foo; |
200 | 200 |
int n; |
201 |
+ int index; |
|
201 | 202 |
|
202 | 203 |
if (val==0 || ((char*)val)[0]==0) |
203 | 204 |
return 0; |
... | ... |
@@ -314,7 +315,7 @@ int parse_tw_append( modparam_t type, void* val) |
314 | 315 |
/* process and optimize the element name */ |
315 | 316 |
if (ha->type==ELEM_IS_AVP) { |
316 | 317 |
/* element is AVP */ |
317 |
- if ( parse_avp_spec( &foo, &n, &avp_name)!=0 ) { |
|
318 |
+ if ( parse_avp_spec( &foo, &n, &avp_name, &index)!=0 ) { |
|
318 | 319 |
LOG(L_ERR,"ERROR:tm:parse_tw_append: bad alias spec " |
319 | 320 |
"<%.*s>\n",foo.len, foo.s); |
320 | 321 |
goto error; |
... | ... |
@@ -67,9 +67,11 @@ |
67 | 67 |
static int fr_timer_avp_type = 0; |
68 | 68 |
static int_str fr_timer_avp = {0}; |
69 | 69 |
static str fr_timer_str; |
70 |
+static int fr_timer_index = 0; |
|
70 | 71 |
static int fr_inv_timer_avp_type = 0; |
71 | 72 |
static int_str fr_inv_timer_avp = {0}; |
72 | 73 |
static str fr_inv_timer_str; |
74 |
+static int fr_inv_timer_index = 0; |
|
73 | 75 |
|
74 | 76 |
|
75 | 77 |
/* ----------------------------------------------------- */ |
... | ... |
@@ -298,7 +300,7 @@ int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param) |
298 | 300 |
fr_timer_str.s = fr_timer_param; |
299 | 301 |
fr_timer_str.len = strlen(fr_timer_str.s); |
300 | 302 |
if (parse_avp_spec( &fr_timer_str, &fr_timer_avp_type, |
301 |
- &fr_timer_avp)<0) { |
|
303 |
+ &fr_timer_avp, &fr_timer_index)<0) { |
|
302 | 304 |
LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_timer " |
303 | 305 |
"AVP specs \"%s\"\n", fr_timer_param); |
304 | 306 |
return -1; |
... | ... |
@@ -309,7 +311,7 @@ int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param) |
309 | 311 |
fr_inv_timer_str.s = fr_inv_timer_param; |
310 | 312 |
fr_inv_timer_str.len = strlen(fr_inv_timer_str.s); |
311 | 313 |
if (parse_avp_spec( &fr_inv_timer_str, &fr_inv_timer_avp_type, |
312 |
- &fr_inv_timer_avp)<0) { |
|
314 |
+ &fr_inv_timer_avp, &fr_inv_timer_index)<0) { |
|
313 | 315 |
LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_inv_timer " |
314 | 316 |
"AVP specs \"%s\"\n", fr_inv_timer_param); |
315 | 317 |
return -1; |
... | ... |
@@ -367,7 +367,7 @@ inline static int comp_num(int op, long left, int rtype, union exp_op* r) |
367 | 367 |
long right; |
368 | 368 |
|
369 | 369 |
if (rtype == AVP_ST) { |
370 |
- avp = search_first_avp(r->attr->type, r->attr->name, &val, 0); |
|
370 |
+ avp = search_avp_by_index(r->attr->type, r->attr->name, &val, r->attr->index); |
|
371 | 371 |
if (avp && !(avp->flags & AVP_VAL_STR)) right = val.n; |
372 | 372 |
else return 0; /* Always fail */ |
373 | 373 |
} else if (rtype == NUMBER_ST) { |
... | ... |
@@ -406,7 +406,7 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r, struct |
406 | 406 |
right=0; /* warning fix */ |
407 | 407 |
|
408 | 408 |
if (rtype == AVP_ST) { |
409 |
- avp = search_first_avp(r->attr->type, r->attr->name, &val, 0); |
|
409 |
+ avp = search_avp_by_index(r->attr->type, r->attr->name, &val, r->attr->index); |
|
410 | 410 |
if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s; |
411 | 411 |
else return 0; |
412 | 412 |
} else if (rtype == SELECT_ST) { |
... | ... |
@@ -531,7 +531,7 @@ inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r, |
531 | 531 |
avp_t* avp; |
532 | 532 |
int_str val; |
533 | 533 |
|
534 |
- avp = search_first_avp(spec->type, spec->name, &val, 0); |
|
534 |
+ avp = search_avp_by_index(spec->type, spec->name, &val, spec->index); |
|
535 | 535 |
if (!avp) return 0; |
536 | 536 |
|
537 | 537 |
switch(op) { |
... | ... |
@@ -30,6 +30,7 @@ |
30 | 30 |
* 2004-10-09 interface more flexible - more function available (bogdan) |
31 | 31 |
* 2004-11-07 AVP string values are kept 0 terminated (bogdan) |
32 | 32 |
* 2004-11-14 global aliases support added |
33 |
+ * 2005-01-05 parse avp name according new syntax |
|
33 | 34 |
*/ |
34 | 35 |
|
35 | 36 |
|
... | ... |
@@ -131,7 +132,7 @@ inline static unsigned short compute_ID( str *name ) |
131 | 132 |
} |
132 | 133 |
|
133 | 134 |
|
134 |
-int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val) |
|
135 |
+avp_t *create_avp (unsigned short flags, int_str name, int_str val) |
|
135 | 136 |
{ |
136 | 137 |
avp_t *avp; |
137 | 138 |
str *s; |
... | ... |
@@ -139,13 +140,11 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v |
139 | 140 |
struct str_str_data *ssd; |
140 | 141 |
int len; |
141 | 142 |
|
142 |
- assert(list != 0); |
|
143 |
- |
|
144 | 143 |
if (name.s.s == 0 && name.s.len == 0) { |
145 | 144 |
LOG(L_ERR,"ERROR:avp:add_avp: 0 ID or NULL NAME AVP!"); |
146 | 145 |
goto error; |
147 | 146 |
} |
148 |
- |
|
147 |
+ |
|
149 | 148 |
/* compute the required mem size */ |
150 | 149 |
len = sizeof(struct usr_avp); |
151 | 150 |
if (flags&AVP_NAME_STR) { |
... | ... |
@@ -168,14 +167,12 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v |
168 | 167 |
avp = (struct usr_avp*)shm_malloc( len ); |
169 | 168 |
if (avp==0) { |
170 | 169 |
LOG(L_ERR,"ERROR:avp:add_avp: no more shm mem\n"); |
171 |
- goto error; |
|
170 |
+ return 0; |
|
172 | 171 |
} |
173 | 172 |
|
174 | 173 |
avp->flags = flags; |
175 | 174 |
avp->id = (flags&AVP_NAME_STR)? compute_ID(&name.s) : name.n ; |
176 |
- |
|
177 |
- avp->next = *list; |
|
178 |
- *list = avp; |
|
175 |
+ avp->next = NULL; |
|
179 | 176 |
|
180 | 177 |
switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) ) |
181 | 178 |
{ |
... | ... |
@@ -213,9 +210,23 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v |
213 | 210 |
ssd->val.s[ssd->val.len] = 0; |
214 | 211 |
break; |
215 | 212 |
} |
216 |
- |
|
217 |
- return 0; |
|
213 |
+ return avp; |
|
218 | 214 |
error: |
215 |
+ return 0; |
|
216 |
+} |
|
217 |
+ |
|
218 |
+int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val) |
|
219 |
+{ |
|
220 |
+ avp_t *avp; |
|
221 |
+ |
|
222 |
+ assert(list != 0); |
|
223 |
+ |
|
224 |
+ if ((avp = create_avp(flags, name, val))) { |
|
225 |
+ avp->next = *list; |
|
226 |
+ *list = avp; |
|
227 |
+ return 0; |
|
228 |
+ } |
|
229 |
+ |
|
219 | 230 |
return -1; |
220 | 231 |
} |
221 | 232 |
|
... | ... |
@@ -242,6 +253,28 @@ int add_avp(unsigned short flags, int_str name, int_str val) |
242 | 253 |
return add_avp_list(list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val); |
243 | 254 |
} |
244 | 255 |
|
256 |
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val) |
|
257 |
+{ |
|
258 |
+ avp_t *new_avp; |
|
259 |
+ |
|
260 |
+ if (!avp) { |
|
261 |
+ return add_avp(flags, name, val); |
|
262 |
+ } |
|
263 |
+ |
|
264 |
+ if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL); |
|
265 |
+ if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL); |
|
266 |
+ |
|
267 |
+ if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) { |
|
268 |
+ ERR("add_avp_before:Source and target AVPs have different CLASS/TRACK\n"); |
|
269 |
+ return -1; |
|
270 |
+ } |
|
271 |
+ if ((new_avp=create_avp(flags, name, val))) { |
|
272 |
+ new_avp->next=avp->next; |
|
273 |
+ avp->next=new_avp; |
|
274 |
+ return 0; |
|
275 |
+ } |
|
276 |
+ return -1; |
|
277 |
+} |
|
245 | 278 |
|
246 | 279 |
/* get value functions */ |
247 | 280 |
inline str* get_avp_name(avp_t *avp) |
... | ... |
@@ -358,6 +391,13 @@ avp_t *search_first_avp(unsigned short flags, int_str name, int_str *val, struct |
358 | 391 |
LOG(L_ERR,"ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!"); |
359 | 392 |
return 0; |
360 | 393 |
} |
394 |
+ |
|
395 |
+ switch (flags & AVP_INDEX_ALL) { |
|
396 |
+ case AVP_INDEX_BACKWARD: |
|
397 |
+ case AVP_INDEX_FORWARD: |
|
398 |
+ WARN("AVP specified with index, but not used for search\n"); |
|
399 |
+ break; |
|
400 |
+ } |
|
361 | 401 |
|
362 | 402 |
if (!s) s = &st; |
363 | 403 |
|
... | ... |
@@ -366,6 +406,17 @@ avp_t *search_first_avp(unsigned short flags, int_str name, int_str *val, struct |
366 | 406 |
* all of them by default |
367 | 407 |
*/ |
368 | 408 |
flags |= AVP_CLASS_ALL; |
409 |
+ |
|
410 |
+ if ((flags & AVP_TRACK_ALL) == 0) { |
|
411 |
+ /* The caller did not specify even the track to search in, so try |
|
412 |
+ * track_from first, and if not found try track_to |
|
413 |
+ */ |
|
414 |
+ ret = search_first_avp(flags | AVP_TRACK_FROM, name, val, s); |
|
415 |
+ if (ret) { |
|
416 |
+ return ret; |
|
417 |
+ } |
|
418 |
+ flags |= AVP_TRACK_TO; |
|
419 |
+ } |
|
369 | 420 |
} |
370 | 421 |
|
371 | 422 |
list = select_list(flags); |
... | ... |
@@ -399,6 +450,13 @@ avp_t *search_next_avp(struct search_state* s, int_str *val ) |
399 | 450 |
return 0; |
400 | 451 |
} |
401 | 452 |
|
453 |
+ switch (s->flags & AVP_INDEX_ALL) { |
|
454 |
+ case AVP_INDEX_BACKWARD: |
|
455 |
+ case AVP_INDEX_FORWARD: |
|
456 |
+ WARN("AVP specified with index, but not used for search\n"); |
|
457 |
+ break; |
|
458 |
+ } |
|
459 |
+ |
|
402 | 460 |
while(1) { |
403 | 461 |
for( ; s->avp; s->avp = s->avp->next) { |
404 | 462 |
if (s->flags & AVP_NAME_RE) { |
... | ... |
@@ -431,6 +489,54 @@ avp_t *search_next_avp(struct search_state* s, int_str *val ) |
431 | 489 |
return 0; |
432 | 490 |
} |
433 | 491 |
|
492 |
+int search_reverse( avp_t *cur, struct search_state* st, |
|
493 |
+ unsigned short index, avp_list_t *ret) |
|
494 |
+{ |
|
495 |
+ unsigned short lvl; |
|
496 |
+ |
|
497 |
+ if (!cur) |
|
498 |
+ return 0; |
|
499 |
+ lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1; |
|
500 |
+ if (index==lvl) |
|
501 |
+ *ret=cur; |
|
502 |
+ return lvl; |
|
503 |
+} |
|
504 |
+ |
|
505 |
+avp_t *search_avp_by_index( unsigned short flags, int_str name, |
|
506 |
+ int_str *val, unsigned short index) |
|
507 |
+{ |
|
508 |
+ avp_t *ret, *cur; |
|
509 |
+ struct search_state st; |
|
510 |
+ |
|
511 |
+ if (flags & AVP_NAME_RE) { |
|
512 |
+ BUG("search_by_index not supported for AVP_NAME_RE\n"); |
|
513 |
+ return 0; |
|
514 |
+ } |
|
515 |
+ switch (flags & AVP_INDEX_ALL) { |
|
516 |
+ case 0: |
|
517 |
+ ret = search_first_avp(flags, name, val, &st); |
|
518 |
+ if (!ret || search_next_avp(&st, NULL)) |
|
519 |
+ return 0; |
|
520 |
+ else |
|
521 |
+ return ret; |
|
522 |
+ case AVP_INDEX_ALL: |
|
523 |
+ BUG("search_by_index not supported for anonymous index []\n"); |
|
524 |
+ return 0; |
|
525 |
+ case AVP_INDEX_FORWARD: |
|
526 |
+ ret = NULL; |
|
527 |
+ cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st); |
|
528 |
+ search_reverse(cur, &st, index, &ret); |
|
529 |
+ if (ret && val) |
|
530 |
+ get_avp_val(ret, val); |
|
531 |
+ return ret; |
|
532 |
+ case AVP_INDEX_BACKWARD: |
|
533 |
+ ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st); |
|
534 |
+ for (index--; (ret && index); ret=search_next_avp(&st, val), index--); |
|
535 |
+ return ret; |
|
536 |
+ } |
|
537 |
+ |
|
538 |
+ return 0; |
|
539 |
+} |
|
434 | 540 |
|
435 | 541 |
/* FIXME */ |
436 | 542 |
/********* free functions ********/ |
... | ... |
@@ -647,16 +753,28 @@ int lookup_avp_galias(str *alias, int *type, int_str *avp_name) |
647 | 753 |
|
648 | 754 |
|
649 | 755 |
/* parsing functions */ |
756 |
+#define ERR_IF_CONTAINS(name,chr) \ |
|
757 |
+ if (memchr(name->s,chr,name->len)) { \ |
|
758 |
+ ERR("Unexpected control character '%c' in AVP name\n", chr); \ |
|
759 |
+ goto error; \ |
|
760 |
+ } |
|
650 | 761 |
|
651 |
-int parse_avp_name( str *name, int *type, int_str *avp_name) |
|
762 |
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index) |
|
652 | 763 |
{ |
653 | 764 |
unsigned int id; |
654 | 765 |
char c; |
766 |
+ char *p; |
|
767 |
+ str s; |
|
655 | 768 |
|
656 |
- if (name==0 || name->s==0 || name->len==0) |
|
769 |
+ if (name==0 || name->s==0 || name->len==0) { |
|
770 |
+ ERR("NULL name or name->s or name->len\n"); |
|
657 | 771 |
goto error; |
772 |
+ } |
|
658 | 773 |
|
659 |
- if (name->len>=2 && name->s[1]==':') { |
|
774 |
+ if (index) *index = 0; |
|
775 |
+ ERR("Parsing '%.*s'\n", name->len, name->s); |
|
776 |
+ if (name->len>=2 && name->s[1]==':') { // old fashion i: or s: |
|
777 |
+ WARN("i: and s: avp name syntax is deprecated!\n"); |
|
660 | 778 |
c = name->s[0]; |
661 | 779 |
name->s += 2; |
662 | 780 |
name->len -= 2; |
... | ... |
@@ -670,17 +788,108 @@ int parse_avp_name( str *name, int *type, int_str *avp_name) |
670 | 788 |
case 'i': case 'I': |
671 | 789 |
*type = 0; |
672 | 790 |
if (str2int( name, &id)!=0) { |
673 |
- LOG(L_ERR, "ERROR:parse_avp_name: invalid ID " |
|
791 |
+ ERR("invalid ID " |
|
674 | 792 |
"<%.*s> - not a number\n", name->len, name->s); |
675 | 793 |
goto error; |
676 | 794 |
} |
677 | 795 |
avp_name->n = (int)id; |
678 | 796 |
break; |
679 | 797 |
default: |
680 |
- LOG(L_ERR, "ERROR:parse_avp_name: unsupported type " |
|
798 |
+ ERR("unsupported type " |
|
681 | 799 |
"[%c]\n", c); |
682 | 800 |
goto error; |
683 | 801 |
} |
802 |
+ } else if ((p=memchr(name->s, '.', name->len))) { |
|
803 |
+ if (p-name->s==1) { |
|
804 |
+ id=name->s[0]; |
|
805 |
+ name->s +=2; |
|
806 |
+ name->len -=2; |
|
807 |
+ } else if (p-name->s==2) { |
|
808 |
+ id=name->s[0]<<8 | name->s[1]; |
|
809 |
+ name->s +=3; |
|
810 |
+ name->len -=3; |
|
811 |
+ } else { |
|
812 |
+ ERR("AVP unknown class prefix '%.*s'\n", p-name->s,name->s); |
|
813 |
+ goto error; |
|
814 |
+ } |
|
815 |
+ if (name->len==0) { |
|
816 |
+ ERR("AVP name not specified after the prefix separator\n"); |
|
817 |
+ goto error; |
|
818 |
+ } |
|
819 |
+ switch (id) { |
|
820 |
+ case 'f': |
|
821 |
+ *type = AVP_TRACK_FROM | AVP_CLASS_USER; |
|
822 |
+ break; |
|
823 |
+ case 't': |
|
824 |
+ *type = AVP_TRACK_TO | AVP_CLASS_USER; |
|
825 |
+ break; |
|
826 |
+ case 0x6664: //'fd' |
|
827 |
+ *type = AVP_TRACK_FROM | AVP_CLASS_DOMAIN; |
|
828 |
+ break; |
|
829 |
+ case 0x7464: // 'td' |
|
830 |
+ *type = AVP_TRACK_TO | AVP_CLASS_DOMAIN; |
|
831 |
+ break; |
|
832 |
+ case 'g': |
|
833 |
+ *type = AVP_TRACK_ALL | AVP_CLASS_GLOBAL; |
|
834 |
+ break; |
|
835 |
+ default: |
|
836 |
+ if (id < 1<<8) |
|
837 |
+ ERR("AVP unknown class prefix '%c'\n", id); |
|
838 |
+ else |
|
839 |
+ ERR("AVP unknown class prefix '%c%c'\n", id>>8,id); |
|
840 |
+ goto error; |
|
841 |
+ } |
|
842 |
+ if (name->s[name->len-1]==']') { |
|
843 |
+ p=memchr(name->s, '[', name->len); |
|
844 |
+ if (!p) { |
|
845 |
+ ERR("missing '[' for AVP index\n"); |
|
846 |
+ goto error; |
|
847 |
+ } |
|
848 |
+ s.s=p+1; |
|
849 |
+ s.len=name->len-(p-name->s)-2; // [ and ] |
|
850 |
+ if (s.len == 0) { |
|
851 |
+ *type |= AVP_INDEX_ALL; |
|
852 |
+ } else { |
|
853 |
+ if (s.s[0]=='-') { |
|
854 |
+ *type |= AVP_INDEX_BACKWARD; |
|
855 |
+ s.s++;s.len--; |
|
856 |
+ } else { |
|
857 |
+ *type |= AVP_INDEX_FORWARD; |
|
858 |
+ } |
|
859 |
+ if ((str2int(&s, &id) != 0)||(id==0)) { |
|
860 |
+ ERR("Invalid AVP index '%.*s'\n", s.len, s.s); |
|
861 |
+ goto error; |
|
862 |
+ } |
|
863 |
+ if (index){ |
|
864 |
+ *index = id; |
|
865 |
+ } else { |
|
866 |
+ WARN("AVP index correcly specified, but called without placeholed\n"); |
|
867 |
+ } |
|
868 |
+ } |
|
869 |
+ name->len=p-name->s; |
|
870 |
+ } |
|
871 |
+ ERR_IF_CONTAINS(name,'.'); |
|
872 |
+ ERR_IF_CONTAINS(name,'['); |
|
873 |
+ ERR_IF_CONTAINS(name,']'); |
|
874 |
+ if ((name->len > 2) && (name->s[0]=='/') && (name->s[name->len-1]=='/')) { |
|
875 |
+ avp_name->re=pkg_malloc(sizeof(regex_t)); |
|
876 |
+ if (!avp_name->re) { |
|
877 |
+ BUG("No free memory to allocate AVP_NAME_RE regex\n"); |
|
878 |
+ goto error; |
|
879 |
+ } |
|
880 |
+ c=name->s[name->len]; |
|
881 |
+ name->s[name->len]=0; |
|
882 |
+ if (regcomp(avp_name->re, name->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) { |
|
883 |
+ pkg_free(avp_name->re); |
|
884 |
+ name->s[name->len] = c; |
|
885 |
+ goto error; |
|
886 |
+ } |
|
887 |
+ *type |= AVP_NAME_RE; |
|
888 |
+ } else { |
|
889 |
+ ERR_IF_CONTAINS(name,'/'); |
|
890 |
+ *type |= AVP_NAME_STR; |
|
891 |
+ } |
|
892 |
+ avp_name->s = *name; |
|
684 | 893 |
} else { |
685 | 894 |
/*default is string name*/ |
686 | 895 |
*type = AVP_NAME_STR; |
... | ... |
@@ -693,7 +902,7 @@ error: |
693 | 902 |
} |
694 | 903 |
|
695 | 904 |
|
696 |
-int parse_avp_spec( str *name, int *type, int_str *avp_name) |
|
905 |
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index) |
|
697 | 906 |
{ |
698 | 907 |
str alias; |
699 | 908 |
|
... | ... |
@@ -710,10 +919,15 @@ int parse_avp_spec( str *name, int *type, int_str *avp_name) |
710 | 919 |
alias.len = name->len-1; |
711 | 920 |
return lookup_avp_galias( &alias, type, avp_name); |
712 | 921 |
} else { |
713 |
- return parse_avp_name( name, type, avp_name); |
|
922 |
+ return parse_avp_name( name, type, avp_name, index); |
|
714 | 923 |
} |
715 | 924 |
} |
716 | 925 |
|
926 |
+void free_avp_name( int *type, int_str *avp_name) |
|
927 |
+{ |
|
928 |
+ if ((*type & AVP_NAME_RE) && (avp_name->re)) |
|
929 |
+ pkg_free(avp_name->re); |
|
930 |
+} |
|
717 | 931 |
|
718 | 932 |
int add_avp_galias_str(char *alias_definition) |
719 | 933 |
{ |
... | ... |
@@ -722,7 +936,8 @@ int add_avp_galias_str(char *alias_definition) |
722 | 936 |
str name; |
723 | 937 |
str alias; |
724 | 938 |
int type; |
725 |
- |
|
939 |
+ int index; |
|
940 |
+ |
|
726 | 941 |
s = alias_definition; |
727 | 942 |
while(*s && isspace((int)*s)) |
728 | 943 |
s++; |
... | ... |
@@ -761,7 +976,7 @@ int add_avp_galias_str(char *alias_definition) |
761 | 976 |
goto parse_error; |
762 | 977 |
} |
763 | 978 |
|
764 |
- if (parse_avp_name( &name, &type, &avp_name)!=0) { |
|
979 |
+ if (parse_avp_name( &name, &type, &avp_name, &index)!=0) { |
|
765 | 980 |
LOG(L_ERR, "ERROR:add_avp_galias_str: <%.*s> not a valid AVP " |
766 | 981 |
"name\n", name.len, name.s); |
767 | 982 |
goto error; |
... | ... |
@@ -52,7 +52,8 @@ |
52 | 52 |
* 7 core avp is in global list |
53 | 53 |
* 8 core avp is in the from avp list |
54 | 54 |
* 9 core avp is in the to avp list |
55 |
- * |
|
55 |
+ * 10 core avp name with positive index |
|
56 |
+ * 11 core avp name with negative index |
|
56 | 57 |
*/ |
57 | 58 |
|
58 | 59 |
#include "str.h" |
... | ... |
@@ -65,6 +66,7 @@ |
65 | 66 |
#define AVP_FR_INV_TIMER "fr_inv_timer" /* Value of final response invite timer */ |
66 | 67 |
#define AVP_RPID "rpid" /* Remote-Party-ID */ |
67 | 68 |
#define AVP_GFLAGS "gflags" /* global flags */ |
69 |
+#define AVP_FLAGS "flags" /* message flags */ |
|
68 | 70 |
|
69 | 71 |
struct str_int_data { |
70 | 72 |
str name; |
... | ... |
@@ -109,6 +111,7 @@ struct search_state { |
109 | 111 |
typedef struct avp_spec { |
110 | 112 |
int type; |
111 | 113 |
int_str name; |
114 |
+ int index; |
|
112 | 115 |
} avp_spec_t; |
113 | 116 |
|
114 | 117 |
/* AVP types */ |
... | ... |
@@ -128,6 +131,11 @@ typedef struct avp_spec { |
128 | 131 |
|
129 | 132 |
#define AVP_CLASS_ALL (AVP_CLASS_USER|AVP_CLASS_DOMAIN|AVP_CLASS_GLOBAL) |
130 | 133 |
|
134 |
+/* AVP name index */ |
|
135 |
+#define AVP_INDEX_FORWARD (1<<10) |
|
136 |
+#define AVP_INDEX_BACKWARD (1<<11) |
|
137 |
+#define AVP_INDEX_ALL (AVP_INDEX_FORWARD | AVP_INDEX_BACKWARD) |
|
138 |
+ |
|
131 | 139 |
#define GALIAS_CHAR_MARKER '$' |
132 | 140 |
|
133 | 141 |
/* Initialize memory structures */ |
... | ... |
@@ -135,6 +143,7 @@ int init_avps(void); |
135 | 143 |
|
136 | 144 |
/* add avp to the list of avps */ |
137 | 145 |
int add_avp(unsigned short flags, int_str name, int_str val); |
146 |
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val); |
|
138 | 147 |
int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val); |
139 | 148 |
|
140 | 149 |
/* Delete avps with given type and name */ |
... | ... |
@@ -145,6 +154,8 @@ avp_t *search_first_avp( unsigned short flags, int_str name, |
145 | 154 |
int_str *val, struct search_state* state); |
146 | 155 |
avp_t *search_next_avp(struct search_state* state, int_str *val); |
147 | 156 |
|
157 |
+avp_t *search_avp_by_index( unsigned short flags, int_str name, |
|
158 |
+ int_str *val, unsigned short index); |
|
148 | 159 |
/* free functions */ |
149 | 160 |
void reset_avps(void); |
150 | 161 |
|
... | ... |
@@ -164,7 +175,8 @@ avp_list_t* set_avp_list(unsigned short flags, avp_list_t* list); |
164 | 175 |
int add_avp_galias_str(char *alias_definition); |
165 | 176 |
int lookup_avp_galias(str *alias, int *type, int_str *avp_name); |
166 | 177 |
int add_avp_galias(str *alias, int type, int_str avp_name); |
167 |
-int parse_avp_name( str *name, int *type, int_str *avp_name); |
|
168 |
-int parse_avp_spec( str *name, int *type, int_str *avp_name); |
|
178 |
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index); |
|
179 |
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index); |
|
180 |
+void free_avp_name( int *type, int_str *avp_name); |
|
169 | 181 |
|
170 | 182 |
#endif |
... | ... |
@@ -178,27 +178,53 @@ static inline int btostr( char *p, unsigned char val) |
178 | 178 |
|
179 | 179 |
#define INT2STR_MAX_LEN (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */ |
180 | 180 |
|
181 |
-/* returns a pointer to a static buffer containing l in asciiz & sets len */ |
|
182 |
-static inline char* int2str(unsigned long l, int* len) |
|
181 |
+/* |
|
182 |
+ * returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len |
|
183 |
+ * left padded with 0 to "size" |
|
184 |
+ */ |
|
185 |
+static inline char* int2str_base_0pad(unsigned int l, int* len, int base, int size) |
|
183 | 186 |
{ |
184 |
- static char r[INT2STR_MAX_LEN]; |
|
185 |
- int i; |
|
186 |
- |
|
187 |
- i=INT2STR_MAX_LEN-2; |
|
188 |
- r[INT2STR_MAX_LEN-1]=0; /* null terminate */ |
|
189 |
- do{ |
|
190 |
- r[i]=l%10+'0'; |
|
191 |
- i--; |
|
192 |
- l/=10; |
|
193 |
- }while(l && (i>=0)); |
|
194 |
- if (l && (i<0)){ |
|
195 |
- LOG(L_CRIT, "BUG: int2str: overflow\n"); |
|
196 |
- } |
|
197 |
- if (len) *len=(INT2STR_MAX_LEN-2)-i; |
|
198 |
- return &r[i+1]; |
|
187 |
+ static char r[INT2STR_MAX_LEN]; |
|
188 |
+ int i, j; |
|
189 |
+ |
|
190 |
+ if (base < 2) { |
|
191 |
+ BUG("base underflow\n"); |
|
192 |
+ return NULL; |
|
193 |
+ } |
|
194 |
+ if (base > 36) { |
|
195 |
+ BUG("base overflow\n"); |
|
196 |
+ return NULL; |
|
197 |
+ } |
|
198 |
+ i=INT2STR_MAX_LEN-2; |
|
199 |
+ j=i-size; |
|
200 |
+ r[INT2STR_MAX_LEN-1]=0; /* null terminate */ |
|
201 |
+ do{ |
|
202 |
+ r[i]=l%base; |
|
203 |
+ if (r[i]<10) |
|
204 |
+ r[i]+='0'; |
|
205 |
+ else |
|
206 |
+ r[i]+='a'-10; |
|
207 |
+ i--; |
|
208 |
+ l/=base; |
|
209 |
+ }while((l || i>j) && (i>=0)); |
|
210 |
+ if (l && (i<0)){ |
|
211 |
+ BUG("result buffer overflow\n"); |
|
212 |
+ } |
|
213 |
+ if (len) *len=(INT2STR_MAX_LEN-2)-i; |
|
214 |
+ return &r[i+1]; |
|
199 | 215 |
} |
200 | 216 |
|
217 |
+/* returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len */ |
|
218 |
+static inline char* int2str_base(unsigned int l, int* len, int base) |
|
219 |
+{ |
|
220 |
+ return int2str_base_0pad(l, len, base, 0); |
|
221 |
+} |
|
201 | 222 |
|
223 |
+/* returns a pointer to a static buffer containing l in asciiz & sets len */ |
|
224 |
+static inline char* int2str(unsigned int l, int* len) |
|
225 |
+{ |
|
226 |
+ return int2str_base(l, len, 10); |
|
227 |
+} |
|
202 | 228 |
|
203 | 229 |
/* faster memchr version */ |
204 | 230 |
static inline char* q_memchr(char* p, int c, unsigned int size) |