Browse Source

- 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 19 years ago
parent
commit
65938e0e15
7 changed files with 410 additions and 6 deletions
  1. 2 0
      cfg.lex
  2. 62 3
      cfg.y
  3. 1 1
      clist.h
  4. 155 2
      flags.c
  5. 5 0
      flags.h
  6. 181 0
      hashes.h
  7. 4 0
      main.c

+ 2 - 0
cfg.lex

@@ -130,6 +130,7 @@ FORCE_TCP_ALIAS		"force_tcp_alias"|"add_tcp_alias"
 SETFLAG		setflag
 RESETFLAG	resetflag
 ISFLAGSET	isflagset
+FLAGS_DECL	"flags"|"bool"
 SET_HOST		"rewritehost"|"sethost"|"seth"
 SET_HOSTPORT	"rewritehostport"|"sethostport"|"sethp"
 SET_USER		"rewriteuser"|"setuser"|"setu"
@@ -331,6 +332,7 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{SETFLAG}	{ count(); yylval.strval=yytext; return SETFLAG; }
 <INITIAL>{RESETFLAG}	{ count(); yylval.strval=yytext; return RESETFLAG; }
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
+<INITIAL>{FLAGS_DECL}	{ count(); yylval.strval=yytext; return FLAGS_DECL; }
 <INITIAL>{MSGLEN}	{ count(); yylval.strval=yytext; return MSGLEN; }
 <INITIAL>{RETCODE}	{ count(); yylval.strval=yytext; return RETCODE; }
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }

+ 62 - 3
cfg.y

@@ -69,6 +69,7 @@
  * 2005-12-19  select framework (mma)
  * 2006-01-06  AVP index support (mma)
  * 2005-01-07  optional semicolon in statement, PARAM_STR&PARAM_STRING
+ * 2006-02-02  named flags support (andrei)
  */
 
 %{
@@ -94,6 +95,7 @@
 #include "ut.h"
 #include "dset.h"
 #include "select.h"
+#include "flags.h"
 
 #include "config.h"
 #ifdef USE_TLS
@@ -275,6 +277,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token MCAST_TTL
 %token TOS
 
+%token FLAGS_DECL
+
 %token ATTR_MARK
 %token SELECT_MARK
 %token ATTR_FROMUSER
@@ -344,6 +348,8 @@ static struct socket_id* mk_listen_id(char*, int, int);
 //%type <intval> class_id
 %type <intval> assign_op
 %type <select> select_id
+%type <strval>	flag_name;
+
 /*%type <route_el> rules;
   %type <route_el> rule;
 */
@@ -361,6 +367,7 @@ statements:
 	;
 statement:
 	assign_stm
+	| flags_decl
 	| module_stm
 	| {rt=REQUEST_ROUTE;} route_stm
 	| {rt=FAILURE_ROUTE;} failure_route_stm
@@ -427,6 +434,27 @@ id_lst:
 	phostport		{  $$=$1 ; }
 	| phostport id_lst	{ $$=$1; $$->next=$2; }
 	;
+
+flags_decl:		FLAGS_DECL	flag_list
+			|	FLAGS_DECL error { yyerror("flag list expected\n") };
+;
+flag_list:		flag_spec
+			|	flag_spec COMMA flag_list
+;
+
+flag_spec:		flag_name	{ if (register_flag($1,-1)<0)
+								yyerror("register flag failed");
+						}
+			|	flag_name COLON NUMBER {
+						if (register_flag($1, $3)<0)
+								yyerror("register flag failed");
+										}
+;
+
+flag_name:		STRING	{ $$=$1; }
+			|	ID		{ $$=$1; }
+;
+
 assign_stm:
 	DEBUG_V EQUAL NUMBER { debug=$3; }
 	| DEBUG_V EQUAL error  { yyerror("number  expected"); }
@@ -1476,11 +1504,42 @@ cmd:
 	| LOG_TOK LPAREN NUMBER COMMA STRING RPAREN	{$$=mk_action(LOG_T, 2, NUMBER_ST, (void*)$3, STRING_ST, $5); }
 	| LOG_TOK error 		{ $$=0; yyerror("missing '(' or ')' ?"); }
 	| LOG_TOK LPAREN error RPAREN	{ $$=0; yyerror("bad log argument"); }
-	| SETFLAG LPAREN NUMBER RPAREN	{$$=mk_action(SETFLAG_T, 1, NUMBER_ST, (void*)$3); }
+	| SETFLAG LPAREN NUMBER RPAREN	{
+							if (check_flag($3)==-1)
+								yyerror("bad flag value");
+							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
+													(void*)$3);
+									}
+	| SETFLAG LPAREN flag_name RPAREN	{
+							i_tmp=get_flag_no($3, strlen($3));
+							if (i_tmp<0) yyerror("flag not declared");
+							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
+										(void*)i_tmp); 
+									}
 	| SETFLAG error			{ $$=0; yyerror("missing '(' or ')'?"); }
-	| RESETFLAG LPAREN NUMBER RPAREN {$$=mk_action(RESETFLAG_T, 1, NUMBER_ST, (void*)$3); }
+	| RESETFLAG LPAREN NUMBER RPAREN {
+							if (check_flag($3)==-1)
+								yyerror("bad flag value");
+							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST, (void*)$3);
+									}
+	| RESETFLAG LPAREN flag_name RPAREN	{
+							i_tmp=get_flag_no($3, strlen($3));
+							if (i_tmp<0) yyerror("flag not declared");
+							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST,
+										(void*)i_tmp); 
+									}
 	| RESETFLAG error		{ $$=0; yyerror("missing '(' or ')'?"); }
-	| ISFLAGSET LPAREN NUMBER RPAREN {$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST, (void*)$3); }
+	| ISFLAGSET LPAREN NUMBER RPAREN {
+							if (check_flag($3)==-1)
+								yyerror("bad flag value");
+							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST, (void*)$3);
+									}
+	| ISFLAGSET LPAREN flag_name RPAREN	{
+							i_tmp=get_flag_no($3, strlen($3));
+							if (i_tmp<0) yyerror("flag not declared");
+							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST,
+										(void*)i_tmp); 
+									}
 	| ISFLAGSET error { $$=0; yyerror("missing '(' or ')'?"); }
 	| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T, 2, STRING_ST, $3, STRING_ST, $5); }
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }

+ 1 - 1
clist.h

@@ -49,7 +49,7 @@
  */
 #define clist_insert_sublist(head, s, e, next, prev) \
 	do{ \
-		(s)->prev=(head); \
+		(s)->prev=(void*)(head); \
 		(e)->next=(head)->next; \
 		(e)->next->prev=(e); \
 		(head)->next=s;   \

+ 155 - 2
flags.c

@@ -28,6 +28,7 @@
  * History:
  * --------
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
+ *  2006-02-02  named flags support (andrei)
  */
 
 
@@ -38,6 +39,7 @@
 #include "flags.h"
 #include "error.h"
 #include "stdlib.h"
+#include "hashes.h"
 
 int setflag( struct sip_msg* msg, flag_t flag ) {
 	msg->flags |= 1 << flag;
@@ -59,15 +61,166 @@ int flag_in_range( flag_t flag ) {
 			flag, MAX_FLAG );
 		return 0;
 	}
-	if (flag<=0) {
+	if (flag<0) {
 		LOG(L_ERR, "ERROR: message flag (%d) must be in range %d..%d\n",
-			flag, 1, MAX_FLAG );
+			flag, 0, MAX_FLAG );
 		return 0;
 	}
 	return 1;
 }
 
 
+/* use 2^k */
+#define FLAGS_NAME_HASH_ENTRIES		32
+
+struct flag_entry{
+	str name;
+	int no;
+	struct flag_entry* next;
+	struct flag_entry* prev;
+};
+
+
+struct flag_hash_head{
+	struct flag_entry* next;
+	struct flag_entry* prev;
+};
+
+static struct flag_hash_head  name2flags[FLAGS_NAME_HASH_ENTRIES];
+static unsigned char registered_flags[MAX_FLAG];
+
+
+void init_named_flags()
+{
+	int r;
+	
+	for (r=0; r<FLAGS_NAME_HASH_ENTRIES; r++)
+		clist_init(&name2flags[r], next, prev);
+}
+
+
+
+/* returns 0 on success, -1 on error */
+int check_flag(int n)
+{
+	if (!flag_in_range(n))
+		return -1;
+	if (registered_flags[n]){
+		LOG(L_WARN, "WARNING: check_flag: flag %d is already used by "
+					" a named flag\n", n);
+	}
+	return 0;
+}
+
+
+inline static struct flag_entry* flag_search(struct flag_hash_head* lst,
+												char* name, int len)
+{
+	struct flag_entry* fe;
+	
+	clist_foreach(lst, fe, next){
+		if ((fe->name.len==len) && (memcmp(fe->name.s, name, len)==0)){
+			/* found */
+			return fe;
+		}
+	}
+	return 0;
+}
+
+
+
+/* returns flag entry or 0 on not found */
+inline static struct flag_entry* get_flag_entry(char* name, int len)
+{
+	int h;
+	/* get hash */
+	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
+	return flag_search(&name2flags[h], name, len);
+}
+
+
+
+/* returns flag number, or -1 on error */
+int get_flag_no(char* name, int len)
+{
+	struct flag_entry* fe;
+	
+	fe=get_flag_entry(name, len);
+	return (fe)?fe->no:-1;
+}
+
+
+
+/* resgiter a new flag name and associates it with pos
+ * pos== -1 => any position will do 
+ * returns flag pos on success (>=0)
+ *         -1  flag is an alias for an already existing flag
+ *         -2  flag already registered
+ *         -3  mem. alloc. failure
+ *         -4  invalid pos
+ *         -5 no free flags */
+int register_flag(char* name, int pos)
+{
+	struct flag_entry* e;
+	int len;
+	unsigned int r;
+	static unsigned int crt_flag=0;
+	unsigned int last_flag;
+	unsigned int h;
+	
+	len=strlen(name);
+	h=get_hash1_raw(name, len) & (FLAGS_NAME_HASH_ENTRIES-1);
+	/* check if the name already exists */
+	e=flag_search(&name2flags[h], name, len);
+	if (e){
+		LOG(L_WARN, "WARNING: register_flag: flag %.*s already registered\n",
+					len, name);
+		return -2;
+	}
+	/* check if there is already another flag registered at pos */
+	if (pos!=-1){
+		if ((pos<0) || (pos>MAX_FLAG)){
+			LOG(L_ERR, "ERROR: register_flag: invalid flag %.*s "
+					"position(%d)\n", len, name, pos);
+			return -4;
+		}
+		if (registered_flags[pos]!=0){
+			LOG(L_WARN, "WARNING: register_flag:  %.*s:  flag %d already in "
+					"use under another name\n", len, name, pos);
+			/* continue */
+		}
+	}else{
+		/* alloc an empty flag */
+		last_flag=crt_flag+MAX_FLAG;
+		for (; crt_flag!=last_flag; crt_flag++){
+			r=crt_flag%MAX_FLAG;
+			if (registered_flags[r]==0){
+				pos=r;
+				break;
+			}
+		}
+		if (pos==-1){
+			LOG(L_ERR, "ERROR: register_flag: could not register %.*s"
+					" - too many flags\n", len, name);
+			return -5;
+		}
+	}
+	registered_flags[pos]++;
+	
+	e=pkg_malloc(sizeof(struct flag_entry));
+	if (e==0){
+		LOG(L_ERR, "ERROR: register_flag: memory allocation failure\n");
+		return -3;
+	}
+	e->name.s=name;
+	e->name.len=len;
+	e->no=pos;
+	clist_insert(&name2flags[h], e, next, prev);
+	return pos;
+}
+
+
+
 #ifdef _GET_AWAY
 
 /* wrapping functions for flag processing  */

+ 5 - 0
flags.h

@@ -45,4 +45,9 @@ int isflagset( struct sip_msg* msg, flag_t flag );
 
 int flag_in_range( flag_t flag );
 
+int register_flag(char* name, int pos);
+int get_flag_no(char* name, int len);
+int check_flag(int pos);
+void init_named_flags();
+
 #endif

+ 181 - 0
hashes.h

@@ -0,0 +1,181 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2006 iptelorg GmbH 
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * History:
+ * --------
+ *  2006-02-02  created by andrei
+ */
+
+
+#ifndef _hashes_h
+#define _hashes_h
+
+#include "str.h"
+#include "mem/mem.h"
+#include "clist.h"
+
+
+
+/* internal use: hash update
+ * params: char* s   - string start,
+ *         char* end - end
+ *         char* p,  and unsigned v temporary vars (used)
+ *         unsigned h - result
+ * h should be initialized (e.g. set it to 0), the result in h */
+#define hash_update_str(s, end, p, v, h) \
+	do{ \
+		for ((p)=(s); (p)<=((end)-4); (p)+=4){ \
+			(v)=(*(p)<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3]; \
+			(h)+=(v)^((v)>>3); \
+		} \
+		(v)=0; \
+		for (;(p)<(end); (p)++){ (v)<<=8; (v)+=*(p);} \
+		(h)+=(v)^((v)>>3); \
+	}while(0)
+
+
+/* internal use: call it to adjust the h from hash_update_str */
+#define hash_finish(h) (((h)+((h)>>11))+(((h)>>13)+((h)>>23)))
+
+
+
+/* "raw" 2 strings hash
+ * returns an unsigned int (which you can use modulo table_size as hash value)
+ */
+inline static unsigned int get_hash2_raw(str* key1, str* key2)
+{
+	char* p;
+	register unsigned v;
+	register unsigned h;
+	
+	h=0;
+	
+	hash_update_str(key1->s, key1->s+key1->len, p, v, h);
+	hash_update_str(key2->s, key2->s+key2->len, p, v, h);
+	return hash_finish(h);
+}
+
+
+
+/* "raw" 1 string hash
+ * returns an unsigned int (which you can use modulo table_size as hash value)
+ */
+inline static unsigned int get_hash1_raw(char* s, int len)
+{
+	char* p;
+	register unsigned v;
+	register unsigned h;
+	
+	h=0;
+	
+	hash_update_str(s, s+len, p, v, h);
+	return hash_finish(h);
+}
+
+
+
+/* generic, simple str keyed hash */
+
+struct str_hash_entry{
+	struct str_hash_entry* next;
+	struct str_hash_entry* prev;
+	str key;
+	unsigned int flags;
+	union{
+		void* p;
+		char* s;
+		int   n;
+		char  data[sizeof(void*)];
+	}u;
+};
+
+
+struct str_hash_head{
+	struct str_hash_entry* next;
+	struct str_hash_entry* prev;
+};
+
+
+struct str_hash_table{
+	struct str_hash_head* table;
+	int size;
+};
+
+
+
+/* returns 0 on success, <0 on failure */
+inline static int str_hash_alloc(struct str_hash_table* ht, int size)
+{
+	ht->table=pkg_malloc(sizeof(struct str_hash_head)*size);
+	if (ht->table==0)
+		return -1;
+	ht->size=size;
+	return 0;
+}
+
+
+
+inline static void str_hash_init(struct str_hash_table* ht)
+{
+	int r;
+	
+	for (r=0; r<ht->size; r++) clist_init(&(ht->table[r]), next, prev);
+}
+
+
+
+inline static void str_hash_add(struct str_hash_table* ht, 
+								struct str_hash_entry* e)
+{
+	int h;
+	
+	h=get_hash1_raw(e->key.s, e->key.len) % ht->size;
+	clist_insert(&ht->table[h], e, next, prev);
+}
+
+
+
+inline static struct str_hash_entry* str_hash_get(struct str_hash_table* ht,
+									char* key, int len)
+{
+	int h;
+	struct str_hash_entry* e;
+	
+	h=get_hash1_raw(e->key.s, e->key.len) % ht->size;
+	clist_foreach(&ht->table[h], e, next){
+		if ((e->key.len==len) && (memcmp(e->key.s, key, len)==0))
+			return e;
+	}
+	return 0;
+}
+
+
+#define str_hash_del(e) clist_rm(e, next, prev)
+
+
+
+#endif

+ 4 - 0
main.c

@@ -127,6 +127,7 @@
 #endif
 #include "usr_avp.h"
 #include "core_cmd.h"
+#include "flags.h"
 
 #include "stats.h"
 
@@ -1340,6 +1341,9 @@ try_again:
 	/*register builtin  modules*/
 	register_builtin_modules();
 
+	/* init named flags */
+	init_named_flags();
+
 	yyin=cfg_stream;
 	debug_save = debug;
 	if ((yyparse()!=0)||(cfg_errors)){