Jelajahi Sumber

- named routes support in core and tm (t_on_*).
e.g.:
route{
route(bar);
t_on_reply("reply_route");
route(1); # == route("1")
...
}
route[foo]{
...
}
route["bar"]{
...
}
route[1]{
...
}
onreply_route[reply_route]{
...
}

route(bar);

Andrei Pelinescu-Onciul 19 tahun lalu
induk
melakukan
93349b4eca
12 mengubah file dengan 422 tambahan dan 127 penghapusan
  1. 2 2
      action.c
  2. 84 30
      cfg.y
  3. 1 1
      hashes.h
  4. 4 2
      main.c
  5. 2 1
      modules/tm/t_fwd.c
  6. 3 2
      modules/tm/t_reply.c
  7. 59 3
      modules/tm/tm.c
  8. 2 2
      onsend.h
  9. 3 3
      receive.c
  10. 224 74
      route.c
  11. 19 6
      route.h
  12. 19 1
      ut.h

+ 2 - 2
action.c

@@ -394,14 +394,14 @@ int do_action(struct action* a, struct sip_msg* msg)
 				ret=E_BUG;
 				break;
 			}
-			if ((a->val[0].u.number>RT_NO)||(a->val[0].u.number<0)){
+			if ((a->val[0].u.number>=main_rt.idx)||(a->val[0].u.number<0)){
 				LOG(L_ERR, "ERROR: invalid routing table number in"
 							"route(%lu)\n", a->val[0].u.number);
 				ret=E_CFG;
 				break;
 			}
 			/*ret=((ret=run_actions(rlist[a->val[0].u.number], msg))<0)?ret:1;*/
-			ret=run_actions(rlist[a->val[0].u.number], msg);
+			ret=run_actions(main_rt.rlist[a->val[0].u.number], msg);
 			last_retcode=ret;
 			run_flags&=~RETURN_R_F; /* absorb returns */
 			break;

+ 84 - 30
cfg.y

@@ -70,6 +70,7 @@
  * 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)
+ * 2006-02-06  named routes support (andrei)
  */
 
 %{
@@ -349,6 +350,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %type <intval> assign_op
 %type <select> select_id
 %type <strval>	flag_name;
+%type <strval>	route_name;
 
 /*%type <route_el> rules;
   %type <route_el> rule;
@@ -851,61 +853,106 @@ ipv6:
 	ipv6addr { $$=$1; }
 	| LBRACK ipv6addr RBRACK {$$=$2; }
 ;
+
+
+route_name:		NUMBER	{
+					tmp=int2str($1, &i_tmp);
+					if (($$=pkg_malloc(i_tmp+1))==0) {
+						yyerror("out of  memory");
+						YYABORT;
+					} else {
+						memcpy($$, tmp, i_tmp);
+						$$[i_tmp]=0;
+					}
+						}
+			|	ID		{ $$=$1; }
+			|	STRING	{ $$=$1; }
+;
+
 route_stm:
-	ROUTE LBRACE actions RBRACE { push($3, &rlist[DEFAULT_RT]); }
-	| ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-		if (($3<RT_NO) && ($3>=0)) {
-			push($6, &rlist[$3]);
-		} else {
-			yyerror("invalid routing table number");
+	ROUTE LBRACE actions RBRACE { push($3, &main_rt.rlist[DEFAULT_RT]); }
+	| ROUTE LBRACK route_name RBRACK LBRACE actions RBRACE {
+		i_tmp=route_get(&main_rt, $3);
+		if (i_tmp==-1){
+			yyerror("internal error");
+			YYABORT;
+		}
+		if (main_rt.rlist[i_tmp]){
+			yyerror("duplicate route");
 			YYABORT;
 		}
+		push($6, &main_rt.rlist[i_tmp]);
 	}
 	| ROUTE error { yyerror("invalid  route  statement"); }
 	;
 failure_route_stm:
-	ROUTE_FAILURE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-		if (($3<FAILURE_RT_NO)&&($3>=1)) {
-			push($6, &failure_rlist[$3]);
-		} else {
-			yyerror("invalid reply routing table number");
+	ROUTE_FAILURE LBRACE actions RBRACE { 
+									push($3, &failure_rt.rlist[DEFAULT_RT]);
+										}
+	| ROUTE_FAILURE LBRACK route_name RBRACK LBRACE actions RBRACE {
+		i_tmp=route_get(&failure_rt, $3);
+		if (i_tmp==-1){
+			yyerror("internal error");
+			YYABORT;
+		}
+		if (failure_rt.rlist[i_tmp]){
+			yyerror("duplicate route");
 			YYABORT;
 		}
+		push($6, &failure_rt.rlist[i_tmp]);
 	}
 	| ROUTE_FAILURE error { yyerror("invalid failure_route statement"); }
 	;
 onreply_route_stm:
-	ROUTE_ONREPLY LBRACE actions RBRACE { push($3, &onreply_rlist[DEFAULT_RT]); }
-	| ROUTE_ONREPLY LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-		if (($3<ONREPLY_RT_NO)&&($3>=1)) {
-			push($6, &onreply_rlist[$3]);
-		} else {
-			yyerror("invalid reply routing table number");
+	ROUTE_ONREPLY LBRACE actions RBRACE {
+									push($3, &onreply_rt.rlist[DEFAULT_RT]);
+										}
+	| ROUTE_ONREPLY LBRACK route_name RBRACK LBRACE actions RBRACE {
+		i_tmp=route_get(&onreply_rt, $3);
+		if (i_tmp==-1){
+			yyerror("internal error");
+			YYABORT;
+		}
+		if (onreply_rt.rlist[i_tmp]){
+			yyerror("duplicate route");
 			YYABORT;
 		}
+		push($6, &onreply_rt.rlist[i_tmp]);
 	}
 	| ROUTE_ONREPLY error { yyerror("invalid onreply_route statement"); }
 	;
 branch_route_stm:
-	ROUTE_BRANCH LBRACE actions RBRACE { push($3, &branch_rlist[DEFAULT_RT]); }
-	| ROUTE_BRANCH LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-		if (($3<BRANCH_RT_NO)&&($3>=1)) {
-			push($6, &branch_rlist[$3]);
-		} else {
-			yyerror("invalid branch routing table number");
+	ROUTE_BRANCH LBRACE actions RBRACE { 
+									push($3, &branch_rt.rlist[DEFAULT_RT]);
+										}
+	| ROUTE_BRANCH LBRACK route_name RBRACK LBRACE actions RBRACE {
+		i_tmp=route_get(&branch_rt, $3);
+		if (i_tmp==-1){
+			yyerror("internal error");
 			YYABORT;
 		}
+		if (branch_rt.rlist[i_tmp]){
+			yyerror("duplicate route");
+			YYABORT;
+		}
+		push($6, &branch_rt.rlist[i_tmp]);
 	}
 	| ROUTE_BRANCH error { yyerror("invalid branch_route statement"); }
 	;
-send_route_stm: ROUTE_SEND LBRACE actions RBRACE {push($3, &onsend_rlist[DEFAULT_RT]); }
-	| ROUTE_SEND LBRACK NUMBER RBRACK LBRACE actions RBRACE {
-		if (($3<ONSEND_RT_NO)&&($3>=1)) {
-			push($6, &onsend_rlist[$3]);
-		} else {
-			yyerror("invalid onsend routing table number");
+send_route_stm: ROUTE_SEND LBRACE actions RBRACE {
+									push($3, &onsend_rt.rlist[DEFAULT_RT]);
+												}
+	| ROUTE_SEND LBRACK route_name RBRACK LBRACE actions RBRACE {
+		i_tmp=route_get(&onsend_rt, $3);
+		if (i_tmp==-1){
+			yyerror("internal error");
+			YYABORT;
+		}
+		if (onsend_rt.rlist[i_tmp]){
+			yyerror("duplicate route");
 			YYABORT;
 		}
+		push($6, &onsend_rt.rlist[i_tmp]);
 	}
 	| ROUTE_SEND error { yyerror("invalid onsend_route statement"); }
 	;
@@ -1544,7 +1591,14 @@ cmd:
 	| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T, 2, STRING_ST, $3, STRING_ST, $5); }
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
 	| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error argument"); }
-	| ROUTE LPAREN NUMBER RPAREN	{ $$=mk_action(ROUTE_T, 1, NUMBER_ST, (void*)$3); }
+	| ROUTE LPAREN route_name RPAREN	{ 
+						i_tmp=route_get(&main_rt, $3);
+						if (i_tmp==-1){
+							yyerror("internal error");
+							YYABORT;
+						}
+						$$=mk_action(ROUTE_T, 1, NUMBER_ST, (void*)i_tmp); 
+										}
 	| ROUTE error { $$=0; yyerror("missing '(' or ')' ?"); }
 	| ROUTE LPAREN error RPAREN { $$=0; yyerror("bad route argument"); }
 	| EXEC LPAREN STRING RPAREN	{ $$=mk_action(EXEC_T, 1, STRING_ST, $3); }

+ 1 - 1
hashes.h

@@ -165,7 +165,7 @@ inline static struct str_hash_entry* str_hash_get(struct str_hash_table* ht,
 	int h;
 	struct str_hash_entry* e;
 	
-	h=get_hash1_raw(e->key.s, e->key.len) % ht->size;
+	h=get_hash1_raw(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;

+ 4 - 2
main.c

@@ -389,6 +389,7 @@ void cleanup(show_status)
 #endif
 	destroy_timer();
 	destroy_script_cb();
+	destroy_routes();
 #ifdef PKG_MALLOC
 	if (show_status){
 		LOG(memlog, "Memory status (pkg):\n");
@@ -1306,7 +1307,8 @@ int main(int argc, char** argv)
 					abort();
 		}
 	}
-
+	
+	if (init_routes()<0) goto error;
 	/* fill missing arguments with the default values*/
 	if (cfg_file==0) cfg_file=CFG_FILE;
 
@@ -1351,7 +1353,7 @@ try_again:
 		goto error;
 	}
 	if (debug_flag) debug = debug_save;
-	print_rl();
+	print_rls();
 
 	/* options with higher priority than cfg file */
 	optind = 1;  /* reset getopt */

+ 2 - 1
modules/tm/t_fwd.c

@@ -47,6 +47,7 @@
  *  2005-12-11  onsend_route support added for forwarding (andrei)
  *  2006-01-27  t_forward_no_ack will return error if a forward on an 
  *              already canceled transaction is attempted (andrei)
+ *  2006-02-07  named routes support (andrei)
  */
 
 #include "defs.h"
@@ -128,7 +129,7 @@ char *print_uac_request( struct cell *t, struct sip_msg *i_req,
 
 	if (branch_route) {
 		     /* run branch_route actions if provided */
-		if (run_actions(branch_rlist[branch_route], i_req) < 0) {
+		if (run_actions(branch_rt.rlist[branch_route], i_req) < 0) {
 			LOG(L_ERR, "ERROR: print_uac_request: Error in run_actions\n");
                }
 	}

+ 3 - 2
modules/tm/t_reply.c

@@ -67,6 +67,7 @@
  *  2005-09-01  reverted to the old way of checking response.dst.send_sock
  *               in t_retransmit_reply & reply_light (andrei)
  *  2005-11-09  updated to the new timers interface (andrei)
+ *  2006-02-07  named routes support (andrei)
  */
 
 
@@ -653,7 +654,7 @@ static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
 		on_failure = t->on_negative;
 		t->on_negative=0;
 		/* run a reply_route action if some was marked */
-		if (run_actions(failure_rlist[on_failure], &faked_req)<0)
+		if (run_actions(failure_rt.rlist[on_failure], &faked_req)<0)
 			LOG(L_ERR, "ERROR: run_failure_handlers: Error in do_action\n");
 	}
 
@@ -1342,7 +1343,7 @@ int reply_received( struct sip_msg  *p_msg )
 		if (t->uas.request) p_msg->flags=t->uas.request->flags;
 		/* set the as avp_list the one from transaction */
 		backup_list = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps );
-		if (run_actions(onreply_rlist[t->on_reply], p_msg)<0)
+		if (run_actions(onreply_rt.rlist[t->on_reply], p_msg)<0)
 			LOG(L_ERR, "ERROR: on_reply processing failed\n");
 		/* transfer current message context back to t */
 		if (t->uas.request) t->uas.request->flags=p_msg->flags;

+ 59 - 3
modules/tm/tm.c

@@ -76,6 +76,7 @@
  *  2005-12-09  fixup_hostport2proxy uses route_struct to access param #1
  *              when fixing param #2
  *  2005-12-09  added t_set_fr() (andrei)
+ *  2006-02-07  named routes support (andrei)
  */
 
 
@@ -94,6 +95,7 @@
 #include "../../usr_avp.h"
 #include "../../mem/mem.h"
 #include "../../route_struct.h"
+#include "../../route.h"
 
 #include "sip_msg.h"
 #include "h_table.h"
@@ -114,6 +116,9 @@ MODULE_VERSION
 
 /* fixup functions */
 static int fixup_hostport2proxy(void** param, int param_no);
+static int fixup_on_failure(void** param, int param_no);
+static int fixup_on_reply(void** param, int param_no);
+static int fixup_on_branch(void** param, int param_no);
 
 
 /* init functions */
@@ -226,11 +231,11 @@ static cmd_export_t cmds[]={
 	{T_FORWARD_NONACK_TLS, w_t_forward_nonack_tls,  2, fixup_hostport2proxy,
 			REQUEST_ROUTE},
 #endif
-	{"t_on_failure",       w_t_on_negative,         1, fixup_int_1,
+	{"t_on_failure",       w_t_on_negative,         1, fixup_on_failure,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
-	{"t_on_reply",         w_t_on_reply,            1, fixup_int_1,
+	{"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
-	{"t_on_branch",       w_t_on_branch,         1, fixup_int_1,
+	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
 			REQUEST_ROUTE | FAILURE_ROUTE },
 	{"t_check_status",     t_check_status,          1, fixup_regex_1,
 			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
@@ -308,6 +313,57 @@ struct module_exports exports= {
 };
 
 
+
+/* helper for fixup_on_* */
+static int fixup_routes(char* r_type, struct route_list* rt, void** param)
+{
+	int i;
+	
+	i=route_get(rt, (char*)*param);
+	if (i==-1){
+		LOG(L_ERR, "ERROR: tm: fixup_routes: route_get failed\n");
+		return E_UNSPEC;
+	}
+	if (rt->rlist[i]==0){
+		LOG(L_WARN, "WARNING: %s(\"%s\"): empty/non existing route\n",
+				r_type, (char*)*param);
+	}
+	*param=(void*)(long)i;
+	return 0;
+}
+
+
+
+static int fixup_on_failure(void** param, int param_no)
+{
+	if (param_no==1){
+		return fixup_routes("t_on_failure", &failure_rt, param);
+	}
+	return 0;
+}
+
+
+
+static int fixup_on_reply(void** param, int param_no)
+{
+	if (param_no==1){
+		return fixup_routes("t_on_reply", &onreply_rt, param);
+	}
+	return 0;
+}
+
+
+
+static int fixup_on_branch(void** param, int param_no)
+{
+	if (param_no==1){
+		return fixup_routes("t_on_branch", &branch_rt, param);
+	}
+	return 0;
+}
+
+
+
 /* (char *hostname, char *port_nr) ==> (struct proxy_l *, -)  */
 static int fixup_hostport2proxy(void** param, int param_no)
 {

+ 2 - 2
onsend.h

@@ -62,13 +62,13 @@ static inline int run_onsend(struct sip_msg* orig_msg,
 	int ret;
 	
 	ret=1;
-	if (onsend_rlist[DEFAULT_RT]){
+	if (onsend_rt.rlist[DEFAULT_RT]){
 		onsnd_info.to=to;
 		onsnd_info.send_sock=send_sock;
 		onsnd_info.buf=buf;
 		onsnd_info.len=len;
 		p_onsend=&onsnd_info;
-		ret=run_actions(onsend_rlist[DEFAULT_RT], orig_msg);
+		ret=run_actions(onsend_rt.rlist[DEFAULT_RT], orig_msg);
 		p_onsend=0; /* reset it */
 	}
 	return ret;

+ 3 - 3
receive.c

@@ -162,7 +162,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 			goto end; /* drop the request */
 
 		/* exec the routing script */
-		if (run_actions(rlist[DEFAULT_RT], msg)<0){
+		if (run_actions(main_rt.rlist[DEFAULT_RT], msg)<0){
 			LOG(L_WARN, "WARNING: receive_msg: "
 					"error while trying script\n");
 			goto error_req;
@@ -202,8 +202,8 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 		if (exec_pre_rpl_cb(msg)==0 )
 			goto end; /* drop the request */
 		/* exec the onreply routing script */
-		if (onreply_rlist[DEFAULT_RT]){
-			ret=run_actions(onreply_rlist[DEFAULT_RT], msg);
+		if (onreply_rt.rlist[DEFAULT_RT]){
+			ret=run_actions(onreply_rt.rlist[DEFAULT_RT], msg);
 			if (ret<0){
 				LOG(L_WARN, "WARNING: receive_msg: "
 						"error while trying onreply script\n");

+ 224 - 74
route.c

@@ -42,7 +42,8 @@
  *  2004-10-19  added from_uri & to_uri (andrei)
  *  2005-12-12  added retcode support (anrei)
  *  2005-12-19  select framework (mma)
- *  2006-01-30 removed rec. protection from eval_expr (andrei)
+ *  2006-01-30  removed rec. protection from eval_expr (andrei)
+ *  2006-02-06  added named route tables (andrei)
  */
 
 
@@ -71,14 +72,181 @@
 #include "mem/mem.h"
 #include "select.h"
 #include "onsend.h"
+#include "hashes.h"
+
+
+#define RT_HASH_SIZE	8 /* route names hash */
 
 /* main routing script table  */
-struct action* rlist[RT_NO];
-/* reply routing table */
-struct action* onreply_rlist[ONREPLY_RT_NO];
-struct action* failure_rlist[FAILURE_RT_NO];
-struct action* branch_rlist[BRANCH_RT_NO];
-struct action* onsend_rlist[ONSEND_RT_NO];
+struct route_list main_rt;
+struct route_list onreply_rt;
+struct route_list failure_rt;
+struct route_list branch_rt;
+struct route_list onsend_rt;
+
+
+
+inline static void destroy_rlist(struct route_list* rt)
+{
+	struct str_hash_entry* e;
+	struct str_hash_entry* tmp;
+
+	if (rt->rlist){
+		pkg_free(rt->rlist);
+		rt->rlist=0;
+		rt->entries=0;
+	}
+	if (rt->names.table){
+		clist_foreach_safe(rt->names.table, e, tmp, next){
+			pkg_free(e);
+		}
+		pkg_free(rt->names.table);
+		rt->names.table=0;
+		rt->names.size=0;
+	}
+}
+
+
+
+void destroy_routes()
+{
+	destroy_rlist(&main_rt);
+	destroy_rlist(&onreply_rt);
+	destroy_rlist(&failure_rt);
+	destroy_rlist(&branch_rt);
+}
+
+
+
+/* adds route name -> i mapping
+ * WARNING: it doesn't check for pre-existing routes 
+ * return -1 on error, route index on success
+ */
+static int route_add(struct route_list* rt, char* name, int i)
+{
+	struct str_hash_entry* e;
+	
+	e=pkg_malloc(sizeof(struct str_hash_entry));
+	if (e==0){
+		LOG(L_CRIT, "ERROR: route_add: out of memory\n");
+		goto error;
+	}
+	e->key.s=name;
+	e->key.len=strlen(name);
+	e->flags=0;
+	e->u.n=i;
+	str_hash_add(&rt->names, e);
+	return 0;
+error:
+	return -1;
+}
+
+
+
+/* returns -1 on error, 0 on success */
+inline  static int init_rlist(char* r_name, struct route_list* rt,
+								int n_entries, int hash_size)
+{
+		rt->rlist=pkg_malloc(sizeof(struct action*)*n_entries);
+		if (rt->rlist==0){ 
+			LOG(L_CRIT, "ERROR: failed to allocate \"%s\" route tables: " 
+					"out of memory\n", r_name); 
+			goto error; 
+		}
+		memset(rt->rlist, 0 , sizeof(struct action*)*n_entries);
+		rt->idx=1; /* idx=0 == default == reserved */
+		rt->entries=n_entries;
+		if (str_hash_alloc(&rt->names, hash_size)<0){
+			LOG(L_CRIT, "ERROR: \"%s\" route table: failed to alloc hash\n",
+					r_name);
+			goto error;
+		}
+		str_hash_init(&rt->names);
+		route_add(rt, "0", 0);  /* default route */
+		
+		return 0;
+error:
+		return -1;
+}
+
+
+
+/* init route tables */
+int init_routes()
+{
+	if (init_rlist("main", &main_rt, RT_NO, RT_HASH_SIZE)<0)
+		goto error;
+	if (init_rlist("on_reply", &onreply_rt, ONREPLY_RT_NO, RT_HASH_SIZE)<0)
+		goto error;
+	if (init_rlist("failure", &failure_rt, FAILURE_RT_NO, RT_HASH_SIZE)<0)
+		goto error;
+	if (init_rlist("branch", &branch_rt, BRANCH_RT_NO, RT_HASH_SIZE)<0)
+		goto error;
+	if (init_rlist("on_send", &onsend_rt, ONSEND_RT_NO, RT_HASH_SIZE)<0)
+		goto error;
+	return 0;
+error:
+	destroy_routes();
+	return -1;
+}
+
+
+
+static inline int route_new_list(struct route_list* rt)
+{
+	int ret;
+	struct action** tmp;
+	
+	ret=-1;
+	if (rt->idx >= rt->entries){
+		tmp=pkg_realloc(rt->rlist, 2*rt->entries*sizeof(struct action*));
+		if (tmp==0){
+			LOG(L_CRIT, "ERROR: route_new_list: out of memory\n");
+			goto end;
+		}
+		rt->rlist=tmp;
+		rt->entries*=2;
+	}
+	if (rt->idx<rt->entries){
+		ret=rt->idx;
+		rt->idx++;
+	}
+end:
+	return ret;
+}
+
+
+
+
+/* 
+ * if the "name" route already exists, return its index, else
+ * create a new empty route
+ * return route index in rt->rlist or -1 on error
+ */
+int route_get(struct route_list* rt, char* name)
+{
+	int len;
+	struct str_hash_entry* e;
+	int i;
+	
+	len=strlen(name);
+	/* check if exists an non empty*/
+	e=str_hash_get(&rt->names, name, len);
+	if (e){
+		i=e->u.n;
+	}else{
+		i=route_new_list(rt);
+		if (i==-1) goto error;
+		if (route_add(rt, name, i)<0){
+			goto error;
+		}
+	}
+	return i;
+error:
+	return -1;
+}
+
+
 
 static int fix_actions(struct action* a); /*fwd declaration*/
 
@@ -983,42 +1151,14 @@ error:
 
 
 
-/* fixes all action tables */
-/* returns 0 if ok , <0 on error */
-int fix_rls()
+static int fix_rl(struct route_list* rt)
 {
-	int i,ret;
-	for(i=0;i<RT_NO;i++){
-		if(rlist[i]){
-			if ((ret=fix_actions(rlist[i]))!=0){
-				return ret;
-			}
-		}
-	}
-	for(i=0;i<ONREPLY_RT_NO;i++){
-		if(onreply_rlist[i]){
-			if ((ret=fix_actions(onreply_rlist[i]))!=0){
-				return ret;
-			}
-		}
-	}
-	for(i=0;i<FAILURE_RT_NO;i++){
-		if(failure_rlist[i]){
-			if ((ret=fix_actions(failure_rlist[i]))!=0){
-				return ret;
-			}
-		}
-	}
-	for(i=0;i<BRANCH_RT_NO;i++){
-		if(branch_rlist[i]){
-			if ((ret=fix_actions(branch_rlist[i]))!=0){
-				return ret;
-			}
-		}
-	}
-	for(i=0;i<ONSEND_RT_NO;i++){
-		if(onsend_rlist[i]){
-			if ((ret=fix_actions(onsend_rlist[i]))!=0){
+	int i;
+	int ret;
+	
+	for(i=0;i<rt->idx; i++){
+		if(rt->rlist[i]){
+			if ((ret=fix_actions(rt->rlist[i]))!=0){
 				return ret;
 			}
 		}
@@ -1027,42 +1167,52 @@ int fix_rls()
 }
 
 
-/* debug function, prints main routing table */
-void print_rl()
+
+/* fixes all action tables */
+/* returns 0 if ok , <0 on error */
+int fix_rls()
 {
-	int j;
+	int ret;
+	
+	if ((ret=fix_rl(&main_rt))!=0)
+		return ret;
+	if ((ret=fix_rl(&onreply_rt))!=0)
+		return ret;
+	if ((ret=fix_rl(&failure_rt))!=0)
+		return ret;
+	if ((ret=fix_rl(&branch_rt))!=0)
+		return ret;
+	if ((ret=fix_rl(&onsend_rt))!=0)
+		return ret;
 
-	for(j=0; j<RT_NO; j++){
-		if (rlist[j]==0){
-			if (j==0) DBG("WARNING: the main routing table is empty\n");
-			continue;
-		}
-		DBG("routing table %d:\n",j);
-		print_actions(rlist[j]);
-		DBG("\n");
-	}
-	for(j=0; j<ONREPLY_RT_NO; j++){
-		if (onreply_rlist[j]==0){
-			continue;
-		}
-		DBG("onreply routing table %d:\n",j);
-		print_actions(onreply_rlist[j]);
-		DBG("\n");
-	}
-	for(j=0; j<FAILURE_RT_NO; j++){
-		if (failure_rlist[j]==0){
-			continue;
-		}
-		DBG("failure routing table %d:\n",j);
-		print_actions(failure_rlist[j]);
-		DBG("\n");
-	}
-	for(j=0; j<BRANCH_RT_NO; j++){
-		if (branch_rlist[j]==0){
+	return 0;
+}
+
+
+
+static void print_rl(struct route_list* rt, char* name)
+{
+	int j;
+	
+	for(j=0; j<rt->entries; j++){
+		if (rt->rlist[j]==0){
+			if ((j==0) && (rt==&main_rt))
+				DBG("WARNING: the main routing table is empty\n");
 			continue;
 		}
-		DBG("branch routing table %d:\n",j);
-		print_actions(branch_rlist[j]);
+		DBG("%s routing table %d:\n", name, j);
+		print_actions(rt->rlist[j]);
 		DBG("\n");
 	}
 }
+
+
+/* debug function, prints routing tables */
+void print_rls()
+{
+	print_rl(&main_rt, "");
+	print_rl(&onreply_rt, "onreply");
+	print_rl(&failure_rt, "failure");
+	print_rl(&branch_rt, "branch");
+	print_rl(&onsend_rt, "onsend");
+}

+ 19 - 6
route.h

@@ -37,22 +37,35 @@
 #include "error.h"
 #include "route_struct.h"
 #include "parser/msg_parser.h"
+#include "hashes.h"
 
 /*#include "cfg_parser.h" */
 
 
+struct route_list{
+	struct action** rlist;
+	int idx; /* first empty entry */ 
+	int entries; /* total number if entries */
+	struct str_hash_table names; /* name to route index mappings */
+};
+
+
 /* main "script table" */
-extern struct action* rlist[RT_NO];
+extern struct route_list main_rt;
 /* main reply route table */
-extern struct action* onreply_rlist[ONREPLY_RT_NO];
-extern struct action* failure_rlist[FAILURE_RT_NO];
-extern struct action* branch_rlist[BRANCH_RT_NO];
-extern struct action* onsend_rlist[ONSEND_RT_NO];
+extern struct route_list onreply_rt;
+extern struct route_list failure_rt;
+extern struct route_list branch_rt;
+extern struct route_list onsend_rt;
+
 
+int init_routes();
+void destroy_routes();
+int route_get(struct route_list* rt, char* name);
 
 void push(struct action* a, struct action** head);
 int add_actions(struct action* a, struct action** head);
-void print_rl();
+void print_rls();
 int fix_rls();
 
 int eval_expr(struct expr* e, struct sip_msg* msg);

+ 19 - 1
ut.h

@@ -220,12 +220,30 @@ static inline char* int2str_base(unsigned int l, int* len, int base)
         return int2str_base_0pad(l, len, base, 0);
 }
 
+
+
 /* returns a pointer to a static buffer containing l in asciiz & sets len */
 static inline char* int2str(unsigned int l, int* len)
 {
-     return int2str_base(l, len, 10);
+	static char r[INT2STR_MAX_LEN];
+	int i;
+	
+	i=INT2STR_MAX_LEN-2;
+	r[INT2STR_MAX_LEN-1]=0; /* null terminate */
+	do{
+		r[i]=l%10+'0';
+		i--;
+		l/=10;
+	}while(l && (i>=0));
+	if (l && (i<0)){
+		LOG(L_CRIT, "BUG: int2str: overflow\n");
+	}
+	if (len) *len=(INT2STR_MAX_LEN-2)-i;
+	return &r[i+1];
 }
 
+
+
 /* faster memchr version */
 static inline char* q_memchr(char* p, int c, unsigned int size)
 {