Browse code

- more generic hash functions - named flags support: the flags can now have names Example: flags a, b:6, test_flag; # b is set to the 6 flag, the rest are # allocated automatically route{ setflag(test_flag); ... }

Andrei Pelinescu-Onciul authored on 02/02/2006 19:29:21
Showing 7 changed files
... ...
@@ -130,6 +130,7 @@ FORCE_TCP_ALIAS		"force_tcp_alias"|"add_tcp_alias"
130 130
 SETFLAG		setflag
131 131
 RESETFLAG	resetflag
132 132
 ISFLAGSET	isflagset
133
+FLAGS_DECL	"flags"|"bool"
133 134
 SET_HOST		"rewritehost"|"sethost"|"seth"
134 135
 SET_HOSTPORT	"rewritehostport"|"sethostport"|"sethp"
135 136
 SET_USER		"rewriteuser"|"setuser"|"setu"
... ...
@@ -331,6 +332,7 @@ EAT_ABLE	[\ \t\b\r]
331 331
 <INITIAL>{SETFLAG}	{ count(); yylval.strval=yytext; return SETFLAG; }
332 332
 <INITIAL>{RESETFLAG}	{ count(); yylval.strval=yytext; return RESETFLAG; }
333 333
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
334
+<INITIAL>{FLAGS_DECL}	{ count(); yylval.strval=yytext; return FLAGS_DECL; }
334 335
 <INITIAL>{MSGLEN}	{ count(); yylval.strval=yytext; return MSGLEN; }
335 336
 <INITIAL>{RETCODE}	{ count(); yylval.strval=yytext; return RETCODE; }
336 337
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
... ...
@@ -69,6 +69,7 @@
69 69
  * 2005-12-19  select framework (mma)
70 70
  * 2006-01-06  AVP index support (mma)
71 71
  * 2005-01-07  optional semicolon in statement, PARAM_STR&PARAM_STRING
72
+ * 2006-02-02  named flags support (andrei)
72 73
  */
73 74
 
74 75
 %{
... ...
@@ -94,6 +95,7 @@
94 94
 #include "ut.h"
95 95
 #include "dset.h"
96 96
 #include "select.h"
97
+#include "flags.h"
97 98
 
98 99
 #include "config.h"
99 100
 #ifdef USE_TLS
... ...
@@ -275,6 +277,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
275 275
 %token MCAST_TTL
276 276
 %token TOS
277 277
 
278
+%token FLAGS_DECL
279
+
278 280
 %token ATTR_MARK
279 281
 %token SELECT_MARK
280 282
 %token ATTR_FROMUSER
... ...
@@ -344,6 +348,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
344 344
 //%type <intval> class_id
345 345
 %type <intval> assign_op
346 346
 %type <select> select_id
347
+%type <strval>	flag_name;
348
+
347 349
 /*%type <route_el> rules;
348 350
   %type <route_el> rule;
349 351
 */
... ...
@@ -361,6 +367,7 @@ statements:
361 361
 	;
362 362
 statement:
363 363
 	assign_stm
364
+	| flags_decl
364 365
 	| module_stm
365 366
 	| {rt=REQUEST_ROUTE;} route_stm
366 367
 	| {rt=FAILURE_ROUTE;} failure_route_stm
... ...
@@ -427,6 +434,27 @@ id_lst:
427 427
 	phostport		{  $$=$1 ; }
428 428
 	| phostport id_lst	{ $$=$1; $$->next=$2; }
429 429
 	;
430
+
431
+flags_decl:		FLAGS_DECL	flag_list
432
+			|	FLAGS_DECL error { yyerror("flag list expected\n") };
433
+;
434
+flag_list:		flag_spec
435
+			|	flag_spec COMMA flag_list
436
+;
437
+
438
+flag_spec:		flag_name	{ if (register_flag($1,-1)<0)
439
+								yyerror("register flag failed");
440
+						}
441
+			|	flag_name COLON NUMBER {
442
+						if (register_flag($1, $3)<0)
443
+								yyerror("register flag failed");
444
+										}
445
+;
446
+
447
+flag_name:		STRING	{ $$=$1; }
448
+			|	ID		{ $$=$1; }
449
+;
450
+
430 451
 assign_stm:
431 452
 	DEBUG_V EQUAL NUMBER { debug=$3; }
432 453
 	| DEBUG_V EQUAL error  { yyerror("number  expected"); }
... ...
@@ -1476,11 +1504,42 @@ cmd:
1476 1476
 	| LOG_TOK LPAREN NUMBER COMMA STRING RPAREN	{$$=mk_action(LOG_T, 2, NUMBER_ST, (void*)$3, STRING_ST, $5); }
1477 1477
 	| LOG_TOK error 		{ $$=0; yyerror("missing '(' or ')' ?"); }
1478 1478
 	| LOG_TOK LPAREN error RPAREN	{ $$=0; yyerror("bad log argument"); }
1479
-	| SETFLAG LPAREN NUMBER RPAREN	{$$=mk_action(SETFLAG_T, 1, NUMBER_ST, (void*)$3); }
1479
+	| SETFLAG LPAREN NUMBER RPAREN	{
1480
+							if (check_flag($3)==-1)
1481
+								yyerror("bad flag value");
1482
+							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
1483
+													(void*)$3);
1484
+									}
1485
+	| SETFLAG LPAREN flag_name RPAREN	{
1486
+							i_tmp=get_flag_no($3, strlen($3));
1487
+							if (i_tmp<0) yyerror("flag not declared");
1488
+							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
1489
+										(void*)i_tmp); 
1490
+									}
1480 1491
 	| SETFLAG error			{ $$=0; yyerror("missing '(' or ')'?"); }
1481
-	| RESETFLAG LPAREN NUMBER RPAREN {$$=mk_action(RESETFLAG_T, 1, NUMBER_ST, (void*)$3); }
1492
+	| RESETFLAG LPAREN NUMBER RPAREN {
1493
+							if (check_flag($3)==-1)
1494
+								yyerror("bad flag value");
1495
+							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST, (void*)$3);
1496
+									}
1497
+	| RESETFLAG LPAREN flag_name RPAREN	{
1498
+							i_tmp=get_flag_no($3, strlen($3));
1499
+							if (i_tmp<0) yyerror("flag not declared");
1500
+							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST,
1501
+										(void*)i_tmp); 
1502
+									}
1482 1503
 	| RESETFLAG error		{ $$=0; yyerror("missing '(' or ')'?"); }
1483
-	| ISFLAGSET LPAREN NUMBER RPAREN {$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST, (void*)$3); }
1504
+	| ISFLAGSET LPAREN NUMBER RPAREN {
1505
+							if (check_flag($3)==-1)
1506
+								yyerror("bad flag value");
1507
+							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST, (void*)$3);
1508
+									}
1509
+	| ISFLAGSET LPAREN flag_name RPAREN	{
1510
+							i_tmp=get_flag_no($3, strlen($3));
1511
+							if (i_tmp<0) yyerror("flag not declared");
1512
+							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST,
1513
+										(void*)i_tmp); 
1514
+									}
1484 1515
 	| ISFLAGSET error { $$=0; yyerror("missing '(' or ')'?"); }
1485 1516
 	| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T, 2, STRING_ST, $3, STRING_ST, $5); }
1486 1517
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
... ...
@@ -49,7 +49,7 @@
49 49
  */
50 50
 #define clist_insert_sublist(head, s, e, next, prev) \
51 51
 	do{ \
52
-		(s)->prev=(head); \
52
+		(s)->prev=(void*)(head); \
53 53
 		(e)->next=(head)->next; \
54 54
 		(e)->next->prev=(e); \
55 55
 		(head)->next=s;   \
... ...
@@ -28,6 +28,7 @@
28 28
  * History:
29 29
  * --------
30 30
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
31
+ *  2006-02-02  named flags support (andrei)
31 32
  */
32 33
 
33 34
 
... ...
@@ -38,6 +39,7 @@
38 38
 #include "flags.h"
39 39
 #include "error.h"
40 40
 #include "stdlib.h"
41
+#include "hashes.h"
41 42
 
42 43
 int setflag( struct sip_msg* msg, flag_t flag ) {
43 44
 	msg->flags |= 1 << flag;
... ...
@@ -59,15 +61,166 @@ int flag_in_range( flag_t flag ) {
59 59
 			flag, MAX_FLAG );
60 60
 		return 0;
61 61
 	}
62
-	if (flag<=0) {
62
+	if (flag<0) {
63 63
 		LOG(L_ERR, "ERROR: message flag (%d) must be in range %d..%d\n",
64
-			flag, 1, MAX_FLAG );
64
+			flag, 0, MAX_FLAG );
65 65
 		return 0;
66 66
 	}
67 67
 	return 1;
68 68
 }
69 69
 
70 70
 
71
+/* use 2^k */
72
+#define FLAGS_NAME_HASH_ENTRIES		32
73
+
74
+struct flag_entry{
75
+	str name;
76
+	int no;
77
+	struct flag_entry* next;
78
+	struct flag_entry* prev;
79
+};
80
+
81
+
82
+struct flag_hash_head{
83
+	struct flag_entry* next;
84
+	struct flag_entry* prev;
85
+};
86
+
87
+static struct flag_hash_head  name2flags[FLAGS_NAME_HASH_ENTRIES];
88
+static unsigned char registered_flags[MAX_FLAG];
89
+
90
+
91
+void init_named_flags()
92
+{
93
+	int r;
94
+	
95
+	for (r=0; r<FLAGS_NAME_HASH_ENTRIES; r++)
96
+		clist_init(&name2flags[r], next, prev);
97
+}
98
+
99
+
100
+
101
+/* returns 0 on success, -1 on error */
102
+int check_flag(int n)
103
+{
104
+	if (!flag_in_range(n))
105
+		return -1;
106
+	if (registered_flags[n]){
107
+		LOG(L_WARN, "WARNING: check_flag: flag %d is already used by "
108
+					" a named flag\n", n);
109
+	}
110
+	return 0;
111
+}
112
+
113
+
114
+inline static struct flag_entry* flag_search(struct flag_hash_head* lst,
115
+												char* name, int len)
116
+{
117
+	struct flag_entry* fe;
118
+	
119
+	clist_foreach(lst, fe, next){
120
+		if ((fe->name.len==len) && (memcmp(fe->name.s, name, len)==0)){
121
+			/* found */
122
+			return fe;
123
+		}
124
+	}
125
+	return 0;
126
+}
127
+
128
+
129
+
130
+/* returns flag entry or 0 on not found */
131
+inline static struct flag_entry* get_flag_entry(char* name, int len)
132
+{
133
+	int h;
134
+	/* get hash */
135
+	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
136
+	return flag_search(&name2flags[h], name, len);
137
+}
138
+
139
+
140
+
141
+/* returns flag number, or -1 on error */
142
+int get_flag_no(char* name, int len)
143
+{
144
+	struct flag_entry* fe;
145
+	
146
+	fe=get_flag_entry(name, len);
147
+	return (fe)?fe->no:-1;
148
+}
149
+
150
+
151
+
152
+/* resgiter a new flag name and associates it with pos
153
+ * pos== -1 => any position will do 
154
+ * returns flag pos on success (>=0)
155
+ *         -1  flag is an alias for an already existing flag
156
+ *         -2  flag already registered
157
+ *         -3  mem. alloc. failure
158
+ *         -4  invalid pos
159
+ *         -5 no free flags */
160
+int register_flag(char* name, int pos)
161
+{
162
+	struct flag_entry* e;
163
+	int len;
164
+	unsigned int r;
165
+	static unsigned int crt_flag=0;
166
+	unsigned int last_flag;
167
+	unsigned int h;
168
+	
169
+	len=strlen(name);
170
+	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
171
+	/* check if the name already exists */
172
+	e=flag_search(&name2flags[h], name, len);
173
+	if (e){
174
+		LOG(L_WARN, "WARNING: register_flag: flag %.*s already registered\n",
175
+					len, name);
176
+		return -2;
177
+	}
178
+	/* check if there is already another flag registered at pos */
179
+	if (pos!=-1){
180
+		if ((pos<0) || (pos>MAX_FLAG)){
181
+			LOG(L_ERR, "ERROR: register_flag: invalid flag %.*s "
182
+					"position(%d)\n", len, name, pos);
183
+			return -4;
184
+		}
185
+		if (registered_flags[pos]!=0){
186
+			LOG(L_WARN, "WARNING: register_flag:  %.*s:  flag %d already in "
187
+					"use under another name\n", len, name, pos);
188
+			/* continue */
189
+		}
190
+	}else{
191
+		/* alloc an empty flag */
192
+		last_flag=crt_flag+MAX_FLAG;
193
+		for (; crt_flag!=last_flag; crt_flag++){
194
+			r=crt_flag%MAX_FLAG;
195
+			if (registered_flags[r]==0){
196
+				pos=r;
197
+				break;
198
+			}
199
+		}
200
+		if (pos==-1){
201
+			LOG(L_ERR, "ERROR: register_flag: could not register %.*s"
202
+					" - too many flags\n", len, name);
203
+			return -5;
204
+		}
205
+	}
206
+	registered_flags[pos]++;
207
+	
208
+	e=pkg_malloc(sizeof(struct flag_entry));
209
+	if (e==0){
210
+		LOG(L_ERR, "ERROR: register_flag: memory allocation failure\n");
211
+		return -3;
212
+	}
213
+	e->name.s=name;
214
+	e->name.len=len;
215
+	e->no=pos;
216
+	clist_insert(&name2flags[h], e, next, prev);
217
+	return pos;
218
+}
219
+
220
+
221
+
71 222
 #ifdef _GET_AWAY
72 223
 
73 224
 /* wrapping functions for flag processing  */
... ...
@@ -45,4 +45,9 @@ int isflagset( struct sip_msg* msg, flag_t flag );
45 45
 
46 46
 int flag_in_range( flag_t flag );
47 47
 
48
+int register_flag(char* name, int pos);
49
+int get_flag_no(char* name, int len);
50
+int check_flag(int pos);
51
+void init_named_flags();
52
+
48 53
 #endif
49 54
new file mode 100644
... ...
@@ -0,0 +1,181 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2006 iptelorg GmbH 
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License 
23
+ * along with this program; if not, write to the Free Software 
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+/*
27
+ * History:
28
+ * --------
29
+ *  2006-02-02  created by andrei
30
+ */
31
+
32
+
33
+#ifndef _hashes_h
34
+#define _hashes_h
35
+
36
+#include "str.h"
37
+#include "mem/mem.h"
38
+#include "clist.h"
39
+
40
+
41
+
42
+/* internal use: hash update
43
+ * params: char* s   - string start,
44
+ *         char* end - end
45
+ *         char* p,  and unsigned v temporary vars (used)
46
+ *         unsigned h - result
47
+ * h should be initialized (e.g. set it to 0), the result in h */
48
+#define hash_update_str(s, end, p, v, h) \
49
+	do{ \
50
+		for ((p)=(s); (p)<=((end)-4); (p)+=4){ \
51
+			(v)=(*(p)<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3]; \
52
+			(h)+=(v)^((v)>>3); \
53
+		} \
54
+		(v)=0; \
55
+		for (;(p)<(end); (p)++){ (v)<<=8; (v)+=*(p);} \
56
+		(h)+=(v)^((v)>>3); \
57
+	}while(0)
58
+
59
+
60
+/* internal use: call it to adjust the h from hash_update_str */
61
+#define hash_finish(h) (((h)+((h)>>11))+(((h)>>13)+((h)>>23)))
62
+
63
+
64
+
65
+/* "raw" 2 strings hash
66
+ * returns an unsigned int (which you can use modulo table_size as hash value)
67
+ */
68
+inline static unsigned int get_hash2_raw(str* key1, str* key2)
69
+{
70
+	char* p;
71
+	register unsigned v;
72
+	register unsigned h;
73
+	
74
+	h=0;
75
+	
76
+	hash_update_str(key1->s, key1->s+key1->len, p, v, h);
77
+	hash_update_str(key2->s, key2->s+key2->len, p, v, h);
78
+	return hash_finish(h);
79
+}
80
+
81
+
82
+
83
+/* "raw" 1 string hash
84
+ * returns an unsigned int (which you can use modulo table_size as hash value)
85
+ */
86
+inline static unsigned int get_hash1_raw(char* s, int len)
87
+{
88
+	char* p;
89
+	register unsigned v;
90
+	register unsigned h;
91
+	
92
+	h=0;
93
+	
94
+	hash_update_str(s, s+len, p, v, h);
95
+	return hash_finish(h);
96
+}
97
+
98
+
99
+
100
+/* generic, simple str keyed hash */
101
+
102
+struct str_hash_entry{
103
+	struct str_hash_entry* next;
104
+	struct str_hash_entry* prev;
105
+	str key;
106
+	unsigned int flags;
107
+	union{
108
+		void* p;
109
+		char* s;
110
+		int   n;
111
+		char  data[sizeof(void*)];
112
+	}u;
113
+};
114
+
115
+
116
+struct str_hash_head{
117
+	struct str_hash_entry* next;
118
+	struct str_hash_entry* prev;
119
+};
120
+
121
+
122
+struct str_hash_table{
123
+	struct str_hash_head* table;
124
+	int size;
125
+};
126
+
127
+
128
+
129
+/* returns 0 on success, <0 on failure */
130
+inline static int str_hash_alloc(struct str_hash_table* ht, int size)
131
+{
132
+	ht->table=pkg_malloc(sizeof(struct str_hash_head)*size);
133
+	if (ht->table==0)
134
+		return -1;
135
+	ht->size=size;
136
+	return 0;
137
+}
138
+
139
+
140
+
141
+inline static void str_hash_init(struct str_hash_table* ht)
142
+{
143
+	int r;
144
+	
145
+	for (r=0; r<ht->size; r++) clist_init(&(ht->table[r]), next, prev);
146
+}
147
+
148
+
149
+
150
+inline static void str_hash_add(struct str_hash_table* ht, 
151
+								struct str_hash_entry* e)
152
+{
153
+	int h;
154
+	
155
+	h=get_hash1_raw(e->key.s, e->key.len) % ht->size;
156
+	clist_insert(&ht->table[h], e, next, prev);
157
+}
158
+
159
+
160
+
161
+inline static struct str_hash_entry* str_hash_get(struct str_hash_table* ht,
162
+									char* key, int len)
163
+{
164
+	int h;
165
+	struct str_hash_entry* e;
166
+	
167
+	h=get_hash1_raw(e->key.s, e->key.len) % ht->size;
168
+	clist_foreach(&ht->table[h], e, next){
169
+		if ((e->key.len==len) && (memcmp(e->key.s, key, len)==0))
170
+			return e;
171
+	}
172
+	return 0;
173
+}
174
+
175
+
176
+#define str_hash_del(e) clist_rm(e, next, prev)
177
+
178
+
179
+
180
+#endif
... ...
@@ -127,6 +127,7 @@
127 127
 #endif
128 128
 #include "usr_avp.h"
129 129
 #include "core_cmd.h"
130
+#include "flags.h"
130 131
 
131 132
 #include "stats.h"
132 133
 
... ...
@@ -1340,6 +1341,9 @@ try_again:
1340 1340
 	/*register builtin  modules*/
1341 1341
 	register_builtin_modules();
1342 1342
 
1343
+	/* init named flags */
1344
+	init_named_flags();
1345
+
1343 1346
 	yyin=cfg_stream;
1344 1347
 	debug_save = debug;
1345 1348
 	if ((yyparse()!=0)||(cfg_errors)){