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