Browse Source

TM callbacks, acc, flags

Jiri Kuthan 23 years ago
parent
commit
3881f12c2c

+ 7 - 7
Makefile.defs

@@ -8,7 +8,7 @@
 VERSION = 0
 PATCHLEVEL = 8
 SUBLEVEL = 7
-EXTRAVERSION = -9
+EXTRAVERSION = -7-ipaq-viadbg
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s)
@@ -81,15 +81,15 @@ ARCH = $(shell uname -m |sed -e s/i.86/i386/ -e s/sun4u/sparc64/ )
 DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DOS='"$(OS)"' -DCOMPILER='"$(CC_VER)"'\
 	 -DDNS_IP_HACK  -DPKG_MALLOC \
-	 -DF_MALLOC -DUSE_SYNONIM\
+	 -DF_MALLOC \
 	 -DSHM_MEM  -DSHM_MMAP \
 	 -DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=1024 \
 	 -DWAIT -DNEW_HNAME \
+	 -DVERY_NOISY_REPLIES\
 	 #-DSILENT_FR \
-	 #-DUSE_SYNONIM\
 	 #-DNO_DEBUG \
+ 	 #-DUSE_SYNONIM\
 	 #-DNOISY_REPLIES \
-	 #-DBOGDAN_TRIFLE \
 	 #-DADAPTIVE_WAIT -DADAPTIVE_WAIT_LOOPS=0 \
 	 #-DNOSMP \
 	 #-DEXTRA_DEBUG 
@@ -102,8 +102,8 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 
 
 #PROFILE=  -pg #set this if you want profiling
-#mode = debug
-mode = release
+mode = debug
+#mode = release
 
 # platform dependent settings
 
@@ -374,7 +374,7 @@ ifeq  ($(OS), SunOS)
 ifeq ($(CC_NAME), suncc)
 	LIBS=-lfast
 endif
-	LIBS+=-ldl -L/usr/local/lib -lfl -lxnet -lrt
+	LIBS+=-ldl -L/usr/local/lib -L/usr/lib/mysql -lfl -lxnet -lrt
 	# -lrt needed for sched_yield
 endif
 

+ 1 - 1
Makefile.sources

@@ -11,7 +11,7 @@
 # defines: sources, objs, depends
 #
 
-sources=$(filter-out $(auto_gen), $(wildcard *.c) $(wildcard mem/*.c) ) $(auto_gen)
+sources=$(filter-out $(auto_gen), $(wildcard *.c) $(wildcard mem/*.c) $(wildcard parser/*.c) ) $(auto_gen)
 objs=$(sources:.c=.o)
 extra_objs=
 depends=$(sources:.c=.d)

+ 49 - 1
action.c

@@ -12,7 +12,7 @@
 #include "forward.h"
 #include "udp_server.h"
 #include "route.h"
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 #include "ut.h"
 #include "sr_module.h"
 #include "mem/mem.h"
@@ -167,6 +167,54 @@ int do_action(struct action* a, struct sip_msg* msg)
 			LOG(a->p1.number, a->p2.string);
 			ret=1;
 			break;
+
+		/* jku - begin : flag processing */
+
+		case SETFLAG_T:
+			if (a->p1_type!=NUMBER_ST) {
+				LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n",
+					a->p1_type );
+				ret=E_BUG;
+				break;
+			}
+			if (!flag_in_range( a->p1.number )) {
+				ret=E_CFG;
+				break;
+			}
+			setflag( msg, a->p1.number );
+			ret=1;
+			break;
+
+		case RESETFLAG_T:
+			if (a->p1_type!=NUMBER_ST) {
+				LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n",
+					a->p1_type );
+				ret=E_BUG;
+				break;
+			}
+			if (!flag_in_range( a->p1.number )) {
+				ret=E_CFG;
+				break;
+			}
+			resetflag( msg, a->p1.number );
+			ret=1;
+			break;
+			
+		case ISFLAGSET_T:
+			if (a->p1_type!=NUMBER_ST) {
+				LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n",
+					a->p1_type );
+				ret=E_BUG;
+				break;
+			}
+			if (!flag_in_range( a->p1.number )) {
+				ret=E_CFG;
+				break;
+			}
+			ret=isflagset( msg, a->p1.number );
+			break;
+		/* jku - end : flag processing */
+
 		case ERROR_T:
 			if ((a->p1_type!=STRING_ST)|(a->p2_type!=STRING_ST)){
 				LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n",

+ 1 - 1
action.h

@@ -6,7 +6,7 @@
 #ifndef action_h
 #define action_h
 
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 #include "route_struct.h"
 
 int do_action(struct action* a, struct sip_msg* msg);

+ 6 - 0
cfg.lex

@@ -46,6 +46,9 @@ LOG		log
 ERROR	error
 ROUTE	route
 EXEC	exec
+SETFLAG		setflag
+RESETFLAG	resetflag
+ISFLAGSET	isflagset
 SET_HOST		"rewritehost"|"sethost"|"seth"
 SET_HOSTPORT	"rewritehostport"|"sethostport"|"sethp"
 SET_USER		"rewriteuser"|"setuser"|"setu"
@@ -131,6 +134,9 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{SEND}	{ count(); yylval.strval=yytext; return SEND; }
 <INITIAL>{LOG}	{ count(); yylval.strval=yytext; return LOG_TOK; }
 <INITIAL>{ERROR}	{ count(); yylval.strval=yytext; return ERROR; }
+<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>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
 <INITIAL>{EXEC}	{ count(); yylval.strval=yytext; return EXEC; }
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }

+ 12 - 2
cfg.y

@@ -62,7 +62,9 @@ void* f_tmp;
 %token ELSE
 %token URIHOST
 %token URIPORT
-
+%token SETFLAG
+%token RESETFLAG
+%token ISFLAGSET
 %token METHOD
 %token URI
 %token SRCIP
@@ -557,13 +559,21 @@ cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
 		| 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, NUMBER_ST, 0,
+													(void *)$3, 0 ); }
+		| SETFLAG error { $$=0; yyerror("missing '(' or ')'?"); }
+		| RESETFLAG LPAREN NUMBER RPAREN {$$=mk_action(	RESETFLAG_T, NUMBER_ST, 0,
+													(void *)$3, 0 ); }
+		| RESETFLAG error { $$=0; yyerror("missing '(' or ')'?"); }
+		| ISFLAGSET LPAREN NUMBER RPAREN {$$=mk_action(	ISFLAGSET_T, NUMBER_ST, 0,
+													(void *)$3, 0 ); }
+		| ISFLAGSET error { $$=0; yyerror("missing '(' or ')'?"); }
 		| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T,
 																STRING_ST, 
 																STRING_ST,
 																$3,
 																$5);
 												  }
-												
 		| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
 		| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error"
 														"argument"); }

+ 1 - 1
data_lump_rpl.h

@@ -6,7 +6,7 @@
 #ifndef data_lump_rpl_h
 #define data_lump_rpl_h
 
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 
 
 struct lump_rpl

+ 245 - 147
etc/iptel.cfg

@@ -1,17 +1,21 @@
 #
-# iptel.org real world configuration
-#
 # $Id$
 #
+# iptel.org real world configuration
+#
+
+# ----------- global configuration parameters ------------------------
 
 debug=3          # debug level (cmd line: -dddddddddd)
-fork=yes
-log_stderror=no	# (cmd line: -E)
-#log_stderror=yes	# (cmd line: -E)
+#fork=yes
+fork=no
+#log_stderror=no	# (cmd line: -E)
+log_stderror=yes	# (cmd line: -E)
 check_via=yes     # (cmd. line: -v)
 dns=on           # (cmd. line: -r)
 rev_dns=yes      # (cmd. line: -R)
-port=5060
+#port=5060
+port=8060
 children=1
 
 # advertise IP address in Via (as opposed to advertising DNS name
@@ -19,9 +23,12 @@ children=1
 # not handle DNS at all)
 listen=195.37.77.101
 
+# ------------------ module loading ----------------------------------
+
 loadmodule "../sip_router/modules/sl/sl.so"
 loadmodule "../sip_router/modules/print/print.so"
 loadmodule "../sip_router/modules/tm/tm.so"
+loadmodule "../sip_router/modules/acc/acc.so"
 loadmodule "../sip_router/modules/rr/rr.so"
 loadmodule "../sip_router/modules/maxfwd/maxfwd.so"
 loadmodule "../sip_router/modules/mysql/mysql.so"
@@ -29,6 +36,10 @@ loadmodule "../sip_router/modules/usrloc/usrloc.so"
 loadmodule "../sip_router/modules/auth/auth.so"
 loadmodule "../sip_router/modules/cpl/cpl.so"
 
+# ----------------- setting module-specific parameters ---------------
+
+# -- usrloc params --
+
 modparam("usrloc", "use_database",   1)
 modparam("usrloc", "table",          "location")
 modparam("usrloc", "user_column",    "user")
@@ -40,16 +51,51 @@ modparam("usrloc", "cseq_column",    "cseq")
 modparam("usrloc", "flush_interval", 60)
 modparam("usrloc", "db_url",         "sql://csps:47csps11@dbhost/csps107")
 
+# -- auth params --
+
 modparam("auth", "db_url",        "sql://csps:47csps11@dbhost/csps107")
 modparam("auth", "user_column",   "user_id")
+# nonce generation secret; particularly useful if multiple servers
+# in a proxy farm are configured to authenticate
 modparam("auth", "secret",        "439tg8h349g8hq349t9384hg")
+# calculate_ha1=false means password column includes ha1 strings;
+# if it was false, plain-text passwords would be assumed
 modparam("auth", "calculate_ha1", false)
 modparam("auth", "nonce_expire",  300)
 modparam("auth", "retry_count",   5)
+# password_column, realm_column, group_table, group_user_column,
+#   group_group_column are set to their default values
+# password_column_2 allows to deal with clients who put domain name
+#   in authentication credentials when calculate_ha1=false (if true,
+#   it works); if set to a value and USER_DOMAIN_HACK was enabled
+#   in defs.h, authentication will still work
 
+# -- acc params --
+# report ACKs too for sake of completeness -- as we account PSTN
+# destinations which are RR, ACKs should show up
+modparam("acc", "report_ack", 1)
+# don't bother me with early media reports (I don't like 183 
+# too much anyway...ever thought of timer C hitting after
+# listening to music-on-hold for five minutes?)
+modparam("acc", "early_media", 0)
+modparam("acc", "log_level", 1)
+# that is the flag for which we will account -- don't forget to
+# set the same one :-)
+modparam("acc", "acc_flag", 1 )
+# we are interested only in succesful transactions
+modparam("acc", "failed_transactions", 0 )
+
+# -- tm params --
+modparam("tm", "fr_timer", 10 )
+modparam("tm", "fr_inv_timer", 30 )
+
+# -------------------------  request routing logic -------------------
+
+# main routing logic
 
 route{
-	# filter local stateless ACK generated by authentication and other replies
+
+	# filter local stateless ACK generated by authentication of mf replies
 	sl_filter_ACK();
 
 	# filter too old messages
@@ -71,163 +117,215 @@ route{
 		break;
 	};
 
+	# if this request is not for our domain, fall over to
+	# outbound request processing; include gateway's address
+	# in matching too -- we RR requests to it, so that
+	# its address may show up in subsequent requests
+	# after rewriteFromRoute
+	
+	if (!(uri=~"[@:]iptel\.org([;:].*)*" 
+		| uri=~"[@:]195\.37\.77\.101([;:].*)*" |
+		uri=~"@195\.37\.77\.110([;:].*)*" )) {
+		route(2);
+	};
+	# here we continue with requests for our domain...
+
 	# various aliases (might use a database in future)
-	if (uri=~"sip:9040@.*") {
-		setuser("jiri");
+	if (uri=~"sip:9040@") {
+		seturi("jiri@iptel.org");
 	};
-	# special measure for our US friends
 	if (uri=~"sip:17@") {
 		seturi("sip:[email protected]");
 	};
+	# check again, if it is still for our domain after aliases
+	if ( !(uri=~"[@:]iptel\.org([;:].*)*" | 
+		uri=~"[@:]195\.37\.77\.101([;:].*)*" |
+		uri=~"@195\.37\.77\.110([;:].*)*" )) {
+		route(2);
+	};
+	log("Request is for iptel.org\n");	
 
-	# process requests for iptel.org (note the wildcard in
-	# the regex end -- that captures URIs which have port
-	# numbers or parameters in them); also include gateway
-	# here too -- we RR to the gateway which means that its
-	# address shows up in d-uri of subsequent requests after
-	# having called rewriteFromRoute and we want the requests
-	# to go through our PSTN authorization code 
-	if (uri=~"[@:]iptel\.org([;:].*)*" | uri=~"[@:]195\.37\.77\.101([;:].*)*" |
-		uri=~"@195\.37\.77\.110([;:].*)*" ) {
-		log("Request is for iptel.org\n");	
-
-		# registers always MUST be authenticated to
-		# avoid stealing incoming calls	
-		if (method=="REGISTER") {
-			log("Request is REGISTER\n");
-			if (!www_authorize("iptel.org", "subscriber")) {
-				log("REGISTER has no credentials, sending challenge\n");
-				www_challenge("iptel.org", "0");
-				break;
-			};
-			# prohibit attempts to grab someone else's address 
-			# using someone else's valid credentials
-			if (!check_to()) {
-				log("Cheating attempt\n");
-				sl_send_reply("403", "What a nasty guy you are");
-				break;
-			};
-				
-			# update Contact database
-        	log("REGISTER is authorized, saving location\n");
-			save_contact("location");
+	# registers always MUST be authenticated to
+	# avoid stealing incoming calls	
+	if (method=="REGISTER") {
+		log("Request is REGISTER\n");
+		if (!www_authorize(	"iptel.org" /* realm */, 
+			 				"subscriber" /* table name */ )) {
+			log("REGISTER has no credentials, sending challenge\n");
+			www_challenge(	"iptel.org" /* realm */, 
+							"0" /* no qop -- M$ can't deal with it */);
+			break;
+		};
+		# prohibit attempts to grab someone else's To address 
+		# using  valid credentials
+		if (!check_to()) {
+			log("To Cheating attempt\n");
+			sl_send_reply("403", "That is ugly -- use To=id next time");
 			break;
 		};
+			
+		# update Contact database
+       	log("REGISTER is authorized, saving location\n");
+		save_contact("location");
+		break;
+	};
 
+	# now check if it's about PSTN destinations through our gateway;
+	# note that 8.... is exempted for numerical destinations
+	if (uri=~"sip:[0-79][0-9]*@.*") {
+		route(3);
+	}; 
 
-		# now it's about PSTN destinations through our gateway;
-		# note that 8.... is exempted for numerical destinations
-		if (uri=~"sip:[0-79][0-9]*@.*") {
-			# free call destinations ... no authentication needed
-			if (uri=~"sip:001795061546@.*" | uri=~"sip:0016097265544.*" | uri=~"sip:[79][0-9][0-9][0-9]@.*") {
-				log("Free PSTN\n");
-			} else {
-				# all other PSTN destinations only for authenticated users
-				# (Cisco GW, which has no digest support, is authenticated
-				# by its IP address -- that's for sure not very strong;
-				# wth confirmed that we filter packets coming from outside
-				# and bearing SRC IP address of a Fokus network)
-				if (!(src_ip==195.37.77.110) & !(proxy_authorize("iptel.org", "subscriber"))) {
-					proxy_challenge("iptel.org", "0");
-					break;
-				};
-			
-				# authorize only for INVITEs -- RR/Contact may result in weird
-				# things showing up in d-uri that would break our logic; our
-				# major concern is INVITE which causes PSTN costs anyway
+	# ---------- demo - begin --------------
+	/* added by Bogdan for cpl demo - Dorgham request*/
+	if (uri=~"sip:test@.*" && method=="INVITE")
+	{
+		log("SER : runing CPL!! :)\n");
+		if ( !cpl_run_script() )
+		{
+   			log("SER : Error during running CPL script!\n");
+		}else{
+   			if ( cpl_is_response_reject() ) {
+				log("SER: reject");
+       			sl_send_reply("603","I am not available!");
+       			break;
+   			}else if ( cpl_is_response_redirect() ) {
+       			log("SER : redirect\n");
+       			cpl_update_contact();
+       			sl_send_reply("302","Moved temporarily");
+       			break;
+   			};
+		};
+	};
+	# -------------- demo - end -------------
 
-				if (method=="INVITE") {
-	
-					# does the authenticated user have a permission for local
-					# calls? (i.e., is he in the "local" group?)
-					if (uri=~"sip:0[1-9][0-9]+@.*") {
-						if (!is_in_group("local")) {
-							sl_send_reply("403", "Local Toodle Noodle...");
-							break;
-						};
-					# the same for long-distance
-					} else if (uri=~"sip:00[1-9][0-9]+@.*") {
-						if (uri=~"sip:001[089]" | uri=~"sip:00900.*" ) {
-								sl_send_reply("403", "Added Value Destinations not permitted...");
-							break;
-						};
-						if (!is_in_group("ld")) {
-							sl_send_reply("403", "LD Toodle Noodle...");
-							break;
-						};
-					# the same for international calls
-					} else if (uri=~"sip:000[1-9][0-9]+@.*") {
-						if (!is_in_group("int")) {
-							sl_send_reply("403", "International Toodle Noodle...");
-							break;
-						};
-					# everything else (e.g., interplanetary calls) is denied
-					} else {
-						sl_send_reply("403", "interplanetary Toodle Noodle...");
-						break;
-					};
+	# native SIP destinations are handled using our USRLOC DB
+	if (!lookup_contact("location")) {
+		log("Unable to lookup contact, sending 404\n");
+		sl_send_reply("404", "Not Found");
+		break;
+	};
+	# check whether some inventive user has uploaded  gateway 
+	# contacts to UsrLoc to bypass our authorization logic
+	if (uri=~"@195\.37\.77\.110([;:].*)*" ) {
+		log("Weird! Gateway address in UsrLoc!\n");
+		route(3);
+	};
 
-				};
-			};
+	# requests from gateway should be RR-ed too
+	if (src_ip==195.37.77.110 && method=="INVITE")  {
+		addRecordRoute();
+	};
 
-			# requests to gateway must be record-route because the GW accepts
-			# only reqeusts coming from our proxy
-			if (method=="INVITE") addRecordRoute();
-			# if you have passed through all the checks, let your call go to GW!
-			rewritehostport("195.37.77.110:5060");
-		} else {
-
-			# non-nummerical destnations now
-
-			# demo stuff *******************************************
-			/* added by Bogdan for cpl demo - Dorgham request*/
-			if (uri=~"sip:test@.*" && method=="INVITE")
-			{
-       			log("SER : runing CPL!! :)\n");
-       			if ( !cpl_run_script() )
-       			{
-           			log("SER : Error during running CPL script!\n");
-       			}else{
-           			if ( cpl_is_response_reject() ) {
-						log("SER: reject");
-               			sl_send_reply("603","I am not available!");
-               			break;
-           			}else if ( cpl_is_response_redirect() ) {
-               			log("SER : redirect\n");
-               			cpl_update_contact();
-               			sl_send_reply("302","Moved temporarily");
-               			break;
-           			};
-       			};
-			};
-			# End of demo stuff *******************************************
+	# we now know we may, we know where, let it go out now!
+	t_relay();
+}
 
-			# native SIP destinations are handled using our USRLOC DB
-			if (!lookup_contact("location")) {
-				log("Unable to lookup contact, sending 404\n");
-				sl_send_reply("404", "Not Found");
-				break;
-			};
-			# requests from gateway should be RR-ed too
-			# (numerical destinations are all RR-ed above)
-			if (src_ip==195.37.77.110 && method=="INVITE")  {
-				addRecordRoute();
-			};
+# routing logic for outbound requests targeted out of our domain
+route[2] {
+		# outbound requests are allowed only for our users -- we don't
+		# support relaying and don't like strangers bothering us
+		# with resolving DNS
+		log("that's a request to outside");
+		if (!(src_ip==195.37.77.110) & 
+			!(proxy_authorize(	"iptel.org" /* realm */,
+							"subscriber" /* table name */ ))) {
+			# see comments bellow on these ACK/CANCEL exceptions
+			if (method=="ACK" ) {
+				log("failed outbound authentication for ACK granted");
+			} else if (method=="CANCEL") {
+				log("failed outbound authentication for ACK granted");
+			} else proxy_challenge("iptel.org" /* realm */, "0" /* no-qop */);
+			break;
 		};
-       } else {
-			# outbound requests are allowed only for our users -- we don't
-			# support relaying and don't like strangers bothering us
-			# with resolving DNS
-			log("that's a request to outside");
-			if (!(src_ip==195.37.77.110) & !(proxy_authorize("iptel.org", "subscriber"))) {
-				proxy_challenge("iptel.org", "0");
-				break;
-			};
-			# there should be check_from here too -- but I'm to tired
-			# to test it tonight
+		# to maintain credibility of our proxy, we check From to be
+		# equal of credential id -- all outbound request leaving our
+		# proxy are guaranteed to be generated by persons in "From"
+		if (!check_from()) {
+			log("From Cheating attempt\n");
+			sl_send_reply("403", "That is ugly -- use From=id next time");
+			break;
 		};
 
-		# we now know we may, we now where, let it go out now!
 		t_relay();
 }
 
+# logic for calls through our PSTN gateway
+route[3] {
+	# free call destinations ... no authentication needed
+	if (uri=~"sip:001795061546@.*" | uri=~"sip:0016097265544.*" 
+		| uri=~"sip:[79][0-9][0-9][0-9]@.*") {
+		log("Free PSTN\n");
+	} else {
+		# all other PSTN destinations only for authenticated users
+		# (Cisco GW, which has no digest support, is authenticated
+		# by its IP address -- that's for sure not very strong;
+		# wth confirmed that we filter packets coming from outside
+		# and bearing SRC IP address of our network)
+		if (!(src_ip==195.37.77.110) & 
+			!(proxy_authorize(	"iptel.org" /* realm */,
+								"subscriber" /* table name */)))  {
+			# we are forgiving and ignore improper credentials
+			# for ACK/CANCEL as bis-09 is somewhat cryptic about
+			# its use and many UACs have not gotten it right
+			if (method=="ACK" ) {
+				log("failed gw authentication for ACK granted");
+			} else if (method=="CANCEL") {
+				log("failed gw authentication for ACK granted");
+			} else proxy_challenge(	"iptel.org" /* realm */, 
+									"0" /* no qop */ );
+			break;
+		};
+		
+		# authorize only for INVITEs -- RR/Contact may result in weird
+		# things showing up in d-uri that would break our logic; our
+		# major concern is INVITE which causes PSTN costs anyway
+
+		if (method=="INVITE") {
+
+			# does the authenticated user have a permission for local
+			# calls? (i.e., is he in the "local" group?)
+			if (uri=~"sip:0[1-9][0-9]+@.*") {
+				if (!is_in_group("local")) {
+					sl_send_reply("403", "Local Toodle Noodle...");
+					break;
+				};
+			# the same for long-distance
+			} else if (uri=~"sip:00[1-9][0-9]+@.*") {
+				if (uri=~"sip:001[089]" | uri=~"sip:00900.*" ) {
+					sl_send_reply("403", "Added Value Destinations not permitted...");
+					break;
+				};
+				if (!is_in_group("ld")) {
+					sl_send_reply("403", "LD Toodle Noodle...");
+					break;
+				};
+			# the same for international calls
+			} else if (uri=~"sip:000[1-9][0-9]+@.*") {
+				if (!is_in_group("int")) {
+					sl_send_reply("403", "International Toodle Noodle...");
+					break;
+				};
+			# everything else (e.g., interplanetary calls) is denied
+			} else {
+				sl_send_reply("403", "interplanetary Toodle Noodle...");
+				break;
+			};
+
+		}; # INVITE to authorized PSTN
+
+	}; # authorized PSTN
+
+	# requests to gateway must be record-route because the GW accepts
+	# only reqeusts coming from our proxy
+	if (method=="INVITE")
+		addRecordRoute();
+
+	# if you have passed through all the checks, let your call go to GW!
+	rewritehostport("195.37.77.110:5060");
+
+	# tag this transaction for accounting
+	setflag(1);
+
+	t_relay();
+}

+ 112 - 0
flags.c

@@ -0,0 +1,112 @@
+/*
+ * $Id$
+ */
+
+#include <limits.h>
+#include "sr_module.h"
+#include "dprint.h"
+#include "parser/msg_parser.h"
+#include "flags.h"
+#include "error.h"
+#include "stdlib.h"
+
+int setflag( struct sip_msg* msg, flag_t flag ) {
+	msg->flags |= 1 << flag;
+	return 1;
+}
+
+int resetflag( struct sip_msg* msg, flag_t flag ) {
+	msg->flags &= ~ flag;
+	return 1;
+}
+
+int isflagset( struct sip_msg* msg, flag_t flag ) {
+	return msg->flags & (1<<flag) ? 1 : -1;
+}
+
+int flag_in_range( flag_t flag ) {
+	if (flag > MAX_FLAG ) {
+		LOG(L_ERR, "ERROR: message flag %d too high; MAX=%d\n",
+			flag, MAX_FLAG );
+		return 0;
+	}
+	if (flag<=0) {
+		LOG(L_ERR, "ERROR: message flag (%d) must be in range %d..%d\n",
+			flag, 1, MAX_FLAG );
+		return 0;
+	}
+	return 1;
+}
+
+
+#ifdef _GET_AWAY
+
+/* wrapping functions for flag processing  */
+static int fixup_t_flag(void** param, int param_no)
+{
+    unsigned int *code;
+	char *c;
+	int token;
+
+	DBG("DEBUG: fixing flag: %s\n", (char *) (*param));
+
+	if (param_no!=1) {
+		LOG(L_ERR, "ERROR: TM module: only parameter #1 for flags can be fixed\n");
+		return E_BUG;
+	};
+
+	if ( !(code = malloc( sizeof( unsigned int) )) ) return E_OUT_OF_MEM;
+
+	*code = 0;
+	c = *param;
+	while ( *c && (*c==' ' || *c=='\t')) c++; /* intial whitespaces */
+
+	token=1;
+	if (strcasecmp(c, "white")==0) *code=FL_WHITE;
+	else if (strcasecmp(c, "yellow")==0) *code=FL_YELLOW;
+	else if (strcasecmp(c, "green")==0) *code=FL_GREEN;
+	else if (strcasecmp(c, "red")==0) *code=FL_RED;
+	else if (strcasecmp(c, "blue")==0) *code=FL_BLUE;
+	else if (strcasecmp(c, "magenta")==0) *code=FL_MAGENTA;
+	else if (strcasecmp(c, "brown")==0) *code=FL_BROWN;
+	else if (strcasecmp(c, "black")==0) *code=FL_BLACK;
+	else if (strcasecmp(c, "acc")==0) *code=FL_ACC;
+	else {
+		token=0;
+		while ( *c && *c>='0' && *c<='9' ) {
+			*code = *code*10+ *c-'0';
+			if (*code > (sizeof( flag_t ) * CHAR_BIT - 1 )) {
+				LOG(L_ERR, "ERROR: TM module: too big flag number: %s; MAX=%d\n",
+					(char *) (*param), sizeof( flag_t ) * CHAR_BIT - 1 );
+				goto error;
+			}
+			c++;
+		}
+	}
+	while ( *c && (*c==' ' || *c=='\t')) c++; /* terminating whitespaces */
+
+	if ( *code == 0 ) {
+		LOG(L_ERR, "ERROR: TM module: bad flag number: %s\n", (char *) (*param));
+		goto error;
+	}
+
+	if (*code < FL_MAX && token==0) {
+		LOG(L_ERR, "ERROR: TM module: too high flag number: %s (%d)\n; lower number"
+			" bellow %d reserved\n", (char *) (*param), *code, FL_MAX );
+		goto error;
+	}
+
+	/* free string */
+	free( *param );
+	/* fix now */
+	*param = code;
+	
+	return 0;
+
+error:
+	free( code );
+	return E_CFG;
+}
+
+
+#endif

+ 24 - 0
flags.h

@@ -0,0 +1,24 @@
+/*
+ * $Id$
+ */
+
+
+#ifndef _FLAGS_H
+#define _FLAGS_H
+
+enum { FL_WHITE=1, FL_YELLOW, FL_GREEN, FL_RED, FL_BLUE, FL_MAGENTA,
+	   FL_BROWN, FL_BLACK, FL_ACC, FL_MAX };
+
+typedef unsigned long flag_t;
+
+#define MAX_FLAG  ( sizeof(flag_t) * CHAR_BIT - 1 )
+
+struct sip_msg;
+
+int setflag( struct sip_msg* msg, flag_t flag );
+int resetflag( struct sip_msg* msg, flag_t flag );
+int isflagset( struct sip_msg* msg, flag_t flag );
+
+int flag_in_range( flag_t flag );
+
+#endif

+ 1 - 1
forward.c

@@ -14,7 +14,7 @@
 
 #include "forward.h"
 #include "config.h"
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 #include "route.h"
 #include "dprint.h"
 #include "udp_server.h"

+ 1 - 1
forward.h

@@ -6,7 +6,7 @@
 #ifndef forward_h
 #define forward_h
 
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 #include "route.h"
 #include "proxy.h"
 

+ 1 - 1
main.c

@@ -30,7 +30,7 @@
 #endif
 #include "sr_module.h"
 #include "timer.h"
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 
 
 #include <signal.h>

+ 1 - 1
modules/tm/config.h

@@ -20,7 +20,7 @@ enum fork_type { DEFAULT, NO_RESPONSE };
 /* FINAL_RESPONSE_TIMER ... tells how long should the transaction engine
    wait if no final response comes back*/
 #define FR_TIME_OUT       30
-#define INV_FR_TIME_OUT   60
+#define INV_FR_TIME_OUT   120
 
 /* WAIT timer ... tells how long state should persist in memory after
    a transaction was finalized*/

+ 3 - 3
modules/tm/h_table.h

@@ -11,10 +11,10 @@
 #include <pthread.h>
 #include <arpa/inet.h>
 
-#include "../../msg_parser.h"
+#include "../../parser/msg_parser.h"
 #include "../../types.h"
 #include "config.h"
-#include "t_flags.h"
+/*#include "t_flags.h"*/
 
 struct s_table;
 struct entry;
@@ -132,7 +132,7 @@ typedef struct cell
 	/* protection against concurrent ACK processing */
 	ser_lock_t	ack_mutex;
 
-	tflags_t	flags;
+/*	tflags_t	flags; */
 
 #ifdef WAIT
 	/* protection against reentering WAIT state */

+ 1 - 1
modules/tm/sip_msg.h

@@ -6,7 +6,7 @@
 #ifndef _SIP_MSG_H
 #define _SIP_MSG_H
 
-#include "../../msg_parser.h"
+#include "../../parser/msg_parser.h"
 
 #include "sh_malloc.h"
 

+ 0 - 20
modules/tm/t_flags.c

@@ -1,20 +0,0 @@
-/*
- * $Id$
- */
-
-
-#include "t_funcs.h"
-
-int t_setflag( unsigned int flag ) {
-	T->flags |= 1 << flag;
-	return 1;
-}
-
-int t_resetflag( unsigned int flag ) {
-	T->flags &= ~ flag;
-	return 1;
-}
-
-int t_isflagset( unsigned int flag ) {
-	return T->flags & (1<<flag) ? 1 : -1;
-}

+ 0 - 26
modules/tm/t_flags.h

@@ -1,26 +0,0 @@
-/*
- * $Id$
- */
-
-
-#ifndef _FLAGS_H
-#define _FLAGS_H
-
-#define FL_WHITE	1
-#define FL_YELLOW	2
-#define FL_GREEN	3
-#define FL_RED		4
-#define FL_BLUE		5
-#define FL_MAGENTA	6
-#define FL_BROWN	7
-#define FL_BLACK	8
-
-
-
-typedef unsigned long tflags_t;
-
-int t_setflag( unsigned int flag );
-int t_resetflag( unsigned int flag );
-int t_isflagset( unsigned int flag );
-
-#endif

+ 1 - 1
modules/tm/t_funcs.c

@@ -7,7 +7,7 @@
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
-#include "../../parser_f.h"
+#include "../../parser/parser_f.h"
 #include "../../ut.h"
 //#include "../../timer.h"
 

+ 3 - 5
modules/tm/t_funcs.h

@@ -10,7 +10,7 @@
 #include <netinet/in.h>
 #include <netdb.h>
 
-#include "../../msg_parser.h"
+#include "../../parser/msg_parser.h"
 #include "../../globals.h"
 #include "../../udp_server.h"
 #include "../../msg_translator.h"
@@ -313,9 +313,7 @@ static inline void set_timer( struct s_table *hash_table,
 {
 	unsigned int timeout;
 	struct timer* list;
-	static enum lists to_table[NR_OF_TIMER_LISTS] = {
-		FR_TIME_OUT, INV_FR_TIME_OUT, WT_TIME_OUT, DEL_TIME_OUT,
-		RETR_T1, RETR_T1 << 1, RETR_T1 << 2, RETR_T2 };
+
 
 	if (list_id<FR_TIMER_LIST || list_id>=NR_OF_TIMER_LISTS) {
 		LOG(L_CRIT, "ERROR: set_timer: unkown list: %d\n", list_id);
@@ -324,7 +322,7 @@ static inline void set_timer( struct s_table *hash_table,
 #endif
 		return;
 	}
-	timeout = to_table[ list_id ];
+	timeout = timer_id2timeout[ list_id ];
 	list= &(hash_table->timers[ list_id ]);
 
 	lock(list->mutex);

+ 9 - 3
modules/tm/t_fwd.c

@@ -7,10 +7,12 @@
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
-#include "../../parser_f.h"
+#include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../timer.h"
 
+#include "t_hooks.h"
+
 
 #define shm_free_lump( _lmp) \
 	do{\
@@ -172,7 +174,8 @@ int t_forward_nonack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 			get_ticks() );
 		/*sets and starts the FINAL RESPONSE timer */
 		set_timer( hash_table, &(T->uac[branch].request.fr_timer),
-			FR_TIMER_LIST );
+			/* p_msg->REQ_METHOD==METHOD_INVITE ? FR_INV_TIMER_LIST : FR_TIMER_LIST ); */
+			FR_TIMER_LIST ); 
 		/* sets and starts the RETRANS timer */
 		T->uac[branch].request.retr_list = RT_T1_TO_1;
 		set_timer( hash_table, &(T->uac[branch].request.retr_timer),
@@ -269,6 +272,7 @@ int t_forward_ack( struct sip_msg* p_msg , unsigned int dest_ip_param ,
 
 	T->uas.isACKed = 1;
 	SEND_PR_BUFFER( &(T->uac[branch].request), ack, len );
+	callback_event( TMCB_E2EACK, p_msg );
 	return attach_ack( T, branch, ack , len );
 
 #ifdef _DON_USE
@@ -354,7 +358,9 @@ int forward_serial_branch(struct cell* Trans,int branch)
 	DBG("DEBUG: t_forward_serial_branch:starting timers (retrans and FR) %d\n",
 		get_ticks() );
 	/*sets and starts the FINAL RESPONSE timer */
-	set_timer( hash_table, &(T->uac[branch].request.fr_timer), FR_TIMER_LIST );
+	set_timer( hash_table, &(T->uac[branch].request.fr_timer), 
+			FR_TIMER_LIST ); 
+			/* p_msg->REQ_METHOD==METHOD_INVITE ? FR_INV_TIMER_LIST : FR_TIMER_LIST ); */
 	/* sets and starts the RETRANS timer */
 	T->uac[branch].request.retr_list = RT_T1_TO_1;
 	set_timer( hash_table, &(T->uac[branch].request.retr_timer), RT_T1_TO_1 );

+ 47 - 0
modules/tm/t_hooks.c

@@ -0,0 +1,47 @@
+/*
+ * $Id$
+ */
+
+
+#include "t_hooks.h"
+
+static struct tm_callback_s* callback_array[ TMCB_END ] = { NULL, NULL } ;
+static int callback_id=0;
+
+/* register a callback function 'f' of type 'cbt'; will be called
+   back whenever the event 'cbt' occurs in transaction module
+*/
+int register_tmcb( tmcb_type cbt, transaction_cb f )
+{
+	struct tm_callback_s *cbs;
+
+	if (cbt<0 || cbt>=TMCB_END ) {
+		LOG(L_ERR, "ERROR: register_tmcb: invalid callback type: %d\n",
+			cbt );
+		return E_BUG;
+	}
+
+	if (!(cbs=malloc( sizeof( struct tm_callback_s)))) {
+		LOG(L_ERR, "ERROR: register_tmcb: out of mem\n");
+		return E_OUT_OF_MEM;
+	}
+
+	callback_id++;
+	cbs->id=callback_id;
+	cbs->callback=f;
+	cbs->next=callback_array[ cbt ];
+	callback_array[ cbt ]=cbs;
+
+	return callback_id;
+}
+
+void callback_event( tmcb_type cbt , struct sip_msg *msg )
+{
+	struct tm_callback_s *cbs;
+
+	DBG("DBG: callback type %d entered\n", cbt );
+	for (cbs=callback_array[ cbt ]; cbs; cbs=cbs->next)  {
+		DBG("DBG: callback id %d entered\n", cbs->id );
+		cbs->callback( T, msg );
+	}
+}

+ 29 - 0
modules/tm/t_hooks.h

@@ -0,0 +1,29 @@
+/*
+ * $Id$
+ */
+
+#ifndef _HOOKS_H
+#define _HOOKS_H
+
+#include "h_table.h"
+#include "t_funcs.h"
+
+typedef enum { TMCB_REPLY,  TMCB_E2EACK, TMCB_END } tmcb_type;
+
+typedef void (transaction_cb) ( struct cell* t, struct sip_msg* msg );
+
+struct tm_callback_s {
+	int id;
+	transaction_cb* callback;
+	struct tm_callback_s* next;
+};
+
+
+extern struct tm_callback_s* callback_array[ TMCB_END ];
+
+typedef int (*register_tmcb_f)(tmcb_type cbt, transaction_cb f);
+
+int register_tmcb( tmcb_type cbt, transaction_cb f );
+void callback_event( tmcb_type cbt, struct sip_msg *msg );
+
+#endif

+ 52 - 48
modules/tm/t_lookup.c

@@ -6,7 +6,7 @@
 #include <assert.h>
 #include "../../dprint.h"
 #include "../../config.h"
-#include "../../parser_f.h"
+#include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../timer.h"
 #include "hash_func.h"
@@ -131,55 +131,55 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 		{ /* it's a ACK request*/
 			/* first only the length are checked */
 			if ( t_msg->first_line.u.request.method_value==METHOD_INVITE
-			&& (fprintf(stderr,"------Method name OK->testing callid len...\n"))
+			/* && (fprintf(stderr,"------Method name OK->testing callid len...\n")) */
 			&& /*callid length*/ EQ_LEN(callid)
-			&& (fprintf(stderr,"------CallID OK -> testing cseq nr len\n"))
+			/* && (fprintf(stderr,"------CallID OK -> testing cseq nr len\n")) */
 			&& get_cseq(t_msg)->number.len==get_cseq(p_msg)->number.len
-			&& (fprintf(stderr,"------Cseq nr OK -> testing from len\n"))
+			/* && (fprintf(stderr,"------Cseq nr OK -> testing from len\n")) */
 			&& /*from length*/ EQ_LEN(from)
-			&& (fprintf(stderr,"------from OK -> testing To uri len\n"))
+			/* && (fprintf(stderr,"------from OK -> testing To uri len\n")) */
 			&& /*to uri*/get_to(t_msg)->uri.len==get_to(p_msg)->uri.len
-			&& (fprintf(stderr,"------To uri OK -> testing To tag len\n"))
+			/* && (fprintf(stderr,"------To uri OK -> testing To tag len\n")) */
 			&& /*to tag*/p_cell->uas.tag->len==get_to(p_msg)->tag_value.len
-			&& (fprintf(stderr,"------To tag OK -> testing uri len\n"))
+			/* && (fprintf(stderr,"------To tag OK -> testing uri len\n")) */
 			&& /*req URI*/(p_cell->uas.status==200 || EQ_REQ_URI_LEN )
-			&& (fprintf(stderr,"------uri OK -> testing via len\n"))
+			/* && (fprintf(stderr,"------uri OK -> testing via len\n")) */
 			&& /*VIA*/(p_cell->uas.status==200 || EQ_VIA_LEN(via1)) )
 				/* so far the lengths are the same
 				-> let's check the contents */
-				if ( fprintf(stderr,"------callid |%.*s| |%.*s|\n",
+				if ( /* fprintf(stderr,"------callid |%.*s| |%.*s|\n",
 					p_msg->callid->body.len,p_msg->callid->body.s,
 					t_msg->callid->body.len,t_msg->callid->body.s)
-				&& /*callid*/!memcmp( t_msg->callid->body.s,
+				&& */ /*callid*/!memcmp( t_msg->callid->body.s,
 					p_msg->callid->body.s,p_msg->callid->body.len)
-				&& fprintf(stderr,"------cseq |%.*s| |%.*s|\n",
+				/* && fprintf(stderr,"------cseq |%.*s| |%.*s|\n",
 					get_cseq(p_msg)->number.len,get_cseq(p_msg)->number.s,
-					get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s)
+					get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s) */
 				&& /*cseq nr*/!memcmp(get_cseq(t_msg)->number.s,
 					get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)
-				&& fprintf(stderr,"------from |%.*s| |%.*s|\n",
+				/* &&  fprintf(stderr,"------from |%.*s| |%.*s|\n",
 					p_msg->from->body.len, translate_pointer(p_msg->orig,
 						p_msg->buf,p_msg->from->body.s),
-					t_msg->from->body.len,t_msg->from->body.s)
+					t_msg->from->body.len,t_msg->from->body.s) */
 				&& /*from*/EQ_STR(from)
-				&& fprintf(stderr,"------to uri |%.*s| |%.*s|\n",
+				/* && fprintf(stderr,"------to uri |%.*s| |%.*s|\n",
 					get_to(p_msg)->uri.len,get_to(p_msg)->uri.s,
-					get_to(t_msg)->uri.len,get_to(t_msg)->uri.s)
+					get_to(t_msg)->uri.len,get_to(t_msg)->uri.s) */
 				&& /*to uri*/!memcmp(get_to(t_msg)->uri.s,
 					get_to(p_msg)->uri.s,get_to(t_msg)->uri.len)
-				&& fprintf(stderr,"------to tag |%.*s| |%.*s|\n",
+				/* && fprintf(stderr,"------to tag |%.*s| |%.*s|\n",
                     get_to(p_msg)->tag_value.len,get_to(p_msg)->tag_value.s,
-                    p_cell->uas.tag->len, p_cell->uas.tag->s)
+                    p_cell->uas.tag->len, p_cell->uas.tag->s) */
 				&& /*to tag*/!memcmp(p_cell->uas.tag->s,
 					get_to(p_msg)->tag_value.s,p_cell->uas.tag->len)
-				&& fprintf(stderr,"------URI %d |%.*s| |%.*s|\n",
+				/* && fprintf(stderr,"------URI %d |%.*s| |%.*s|\n",
 					p_cell->uas.status,p_msg->first_line.u.request.uri.len,
 					translate_pointer(p_msg->orig, p_msg->buf,
 						p_msg->first_line.u.request.uri.s),
 					t_msg->first_line.u.request.uri.len,
-					t_msg->first_line.u.request.uri.s)
+					t_msg->first_line.u.request.uri.s) */
 				&& /*req URI*/(p_cell->uas.status==200 || EQ_REQ_URI_STR)
-				&& fprintf(stderr,"------VIA %d |%.*s| |%.*s|\n",
+				/* && fprintf(stderr,"------VIA %d |%.*s| |%.*s|\n",
 					p_cell->uas.status, 
 					(p_msg->via1->bsize-(p_msg->via1->name.s-
 						(p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
@@ -187,7 +187,7 @@ int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
 						p_msg->via1->name.s),
                     (t_msg->via1->bsize-(t_msg->via1->name.s-
 						(t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
-					t_msg->via1->name.s)
+					t_msg->via1->name.s) */
 				&& /*VAI*/(p_cell->uas.status==200 ||EQ_VIA_STR(via1)) )
 					{ /* WE FOUND THE GOLDEN EGG !!!! */
 						goto found;
@@ -245,67 +245,67 @@ struct cell* t_lookupOriginalT(  struct s_table* hash_table ,
 
 		/* is it the wanted transaction ? */
 		/* first only the length are checked */
-		if ( fprintf(stderr,"starting\n") && p_cell->uas.request->REQ_METHOD!=METHOD_CANCEL
-			&& fprintf(stderr,"checking callid length....\n")
+		if ( /* fprintf(stderr,"starting\n")  && */ p_cell->uas.request->REQ_METHOD!=METHOD_CANCEL
+			/* && fprintf(stderr,"checking callid length....\n") */
 			&& /*callid length*/ EQ_LEN(callid)
-			&& fprintf(stderr,"OK. checking cseg nr len....\n")	
+			/* && fprintf(stderr,"OK. checking cseg nr len....\n")	 */
 			&& get_cseq(t_msg)->number.len==get_cseq(p_msg)->number.len
-			&& fprintf(stderr,"OK. checking REQ_URI len.... \n")
+			/* && fprintf(stderr,"OK. checking REQ_URI len.... \n") */
 			&& EQ_REQ_URI_LEN
-			&& fprintf(stderr,"OK. checking VIA %d %d....\n",
+			/* && fprintf(stderr,"OK. checking VIA %d %d....\n",
 				(p_msg->via1->bsize-(p_msg->via1->name.s-
 					(p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
 				(t_msg->via1->bsize-(t_msg->via1->name.s-
-					(t_msg->via1->hdr.s+t_msg->via1->hdr.len))))
-            && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
+					(t_msg->via1->hdr.s+t_msg->via1->hdr.len)))) */
+            /* && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
                 (p_msg->via1->bsize-(p_msg->via1->name.s-
                      (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
                 translate_pointer(p_msg->orig,p_msg->buf,
                        p_msg->via1->name.s),
                 (t_msg->via1->bsize-(t_msg->via1->name.s-
                       (t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
-                t_msg->via1->name.s)
+                t_msg->via1->name.s) */
 			&& EQ_VIA_LEN(via1) 
-			&& fprintf(stderr,"OK. checking FROM len... \n")
+			/* && fprintf(stderr,"OK. checking FROM len... \n") */
 			&& EQ_LEN(from)
-			&& fprintf(stderr,"OK. checking TO len... \n")
+			/* && fprintf(stderr,"OK. checking TO len... \n") */
 			&& EQ_LEN(to)
-			&& fprintf(stderr,"OK\n") )
+			/* && fprintf(stderr,"OK\n") */ )
 				/* so far the lengths are the same
 				 let's check the contents */
 				if (
-                	fprintf(stderr,"checking callid |%.*s| |%.*s|\n",
+                	/* fprintf(stderr,"checking callid |%.*s| |%.*s|\n",
                     	p_msg->callid->body.len, translate_pointer(p_msg->orig,
                         	p_msg->buf,p_msg->callid->body.s),
-                    	t_msg->callid->body.len,t_msg->callid->body.s)
-					&& /*callid*/ EQ_STR(callid)
-					&& fprintf(stderr,"OK. cseq nr |%.*s| |%.*s|\n",
+                    	t_msg->callid->body.len,t_msg->callid->body.s) 
+					&& *//*callid*/ EQ_STR(callid)
+					/* && fprintf(stderr,"OK. cseq nr |%.*s| |%.*s|\n",
 						get_cseq(p_msg)->number.len,get_cseq(p_msg)->number.s,
-						get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s)
+						get_cseq(t_msg)->number.len,get_cseq(t_msg)->number.s) */
 					&& /*cseq_nr*/ !memcmp(get_cseq(t_msg)->number.s,
 						get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)
-	                && fprintf(stderr,"OK. URI %d |%.*s| |%.*s|\n",
+	                /* && fprintf(stderr,"OK. URI %d |%.*s| |%.*s|\n",
                     	p_cell->uas.status,p_msg->first_line.u.request.uri.len,
                     	translate_pointer(p_msg->orig, p_msg->buf,
                         	p_msg->first_line.u.request.uri.s),
                     	t_msg->first_line.u.request.uri.len,
-                    	t_msg->first_line.u.request.uri.s)
+                    	t_msg->first_line.u.request.uri.s) */
 					&& EQ_REQ_URI_STR
-	                && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
+	                /* && fprintf(stderr,"OK. VIA |%.*s| |%.*s|\n",
         	            (p_msg->via1->bsize-(p_msg->via1->name.s-
             	            (p_msg->via1->hdr.s+p_msg->via1->hdr.len))),
                 	    translate_pointer(p_msg->orig,p_msg->buf,
                     	    p_msg->via1->name.s),
            				(t_msg->via1->bsize-(t_msg->via1->name.s-
                     	    (t_msg->via1->hdr.s+t_msg->via1->hdr.len))),
-						t_msg->via1->name.s)
+						t_msg->via1->name.s) */
 					&& EQ_VIA_STR(via1)
-	                && fprintf(stderr,"OK. from |%.*s| |%.*s|\n",
+	                /* && fprintf(stderr,"OK. from |%.*s| |%.*s|\n",
                         p_msg->from->body.len, translate_pointer(p_msg->orig,
                             p_msg->buf,p_msg->from->body.s),
-                        t_msg->from->body.len,t_msg->from->body.s)
+                        t_msg->from->body.len,t_msg->from->body.s) */
 					&& EQ_STR(from)
-					&& fprintf(stderr,"OK\n") )
+					/* && fprintf(stderr,"OK\n") */ )
 					{ /* WE FOUND THE GOLDEN EGG !!!! */
 						DBG("DEBUG: t_lookupOriginalT: canceled transaction"
 							" found (%p)! \n",p_cell );
@@ -559,9 +559,13 @@ enum addifnew_status t_addifnew( struct sip_msg* p_msg )
 	struct cell *new_cell;
 
 	/* is T still up-to-date ? */
-	DBG("DEBUG: t_check_new_request: msg id=%d , global msg id=%d ,"
+	DBG("DEBUG: t_addifnew: msg id=%d , global msg id=%d ,"
 		" T on entrance=%p\n",p_msg->id,global_msg_id,T);
-	if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
+	if ( p_msg->id != global_msg_id || T==T_UNDEFINED 
+		/* if someone tried to do something previously by mistake with
+		   a transaction which did not exist yet, try to look-up
+		   the transacion too */
+		|| T==T_NULL)
 	{
 		global_msg_id = p_msg->id;
 		T = T_UNDEFINED;
@@ -604,7 +608,7 @@ enum addifnew_status t_addifnew( struct sip_msg* p_msg )
 		}
 	} else {
 		if (T)
-			LOG(L_ERR, "ERROR: t_check_new_request: already "
+			LOG(L_ERR, "ERROR: t_addifnew: already "
 			"processing this message, T found!\n");
 		else
 			LOG(L_ERR, "ERROR: t_check_new_request: already "

+ 7 - 3
modules/tm/t_reply.c

@@ -8,10 +8,12 @@
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
-#include "../../parser_f.h"
+#include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../timer.h"
 
+#include "t_hooks.h"
+
 
 
 
@@ -38,11 +40,11 @@ int t_retransmit_reply( /* struct sip_msg* p_msg    */ )
 	int len;
 
 	if (!T->uas.response.buffer)
-		return 0;
+		return -1;
 
 	if ( (len=T->uas.response.buffer_len)==0 || len>BUF_SIZE ) {
 		UNLOCK_REPLIES( T );
-		return -1;
+		return -2;
 	}
 	memcpy( b, T->uas.response.buffer, len );
 	UNLOCK_REPLIES( T );
@@ -370,6 +372,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 	if (relay >= 0) {
 		SEND_PR_BUFFER( rb, buf, res_len );
 		t_update_timers_after_sending_reply( rb );
+		callback_event( TMCB_REPLY, p_msg );
 	}
 
 	/* *** ACK handling *** */
@@ -378,6 +381,7 @@ int t_on_reply( struct sip_msg  *p_msg )
 		{   /*retransmit*/
 			/* I don't need any additional syncing here -- after ack
 			   is introduced it's never changed */
+			DBG("DEBUG: localy cached ACK retranmitted\n");
 			SEND_ACK_BUFFER( &(T->uac[branch].request) );
 		} else if (msg_class>2 ) {
 			/*on a non-200 reply to INVITE*/

+ 14 - 1
modules/tm/timer.c

@@ -17,7 +17,20 @@ int timer_group[NR_OF_TIMER_LISTS] =
 	TG_RT, TG_RT, TG_RT, TG_RT
 };
 
-
+/* default values of timeouts for all the timer list
+   (see timer.h for enumeration of timer lists)
+*/
+unsigned int timer_id2timeout[NR_OF_TIMER_LISTS] = {
+	FR_TIME_OUT, 		/* FR_TIMER_LIST */
+	INV_FR_TIME_OUT, 	/* FR_INV_TIMER_LIST */
+	WT_TIME_OUT, 		/* WT_TIMER_LIST */
+	DEL_TIME_OUT,		/* DELETE_LIST */
+	RETR_T1, 			/* RT_T1_TO_1 */
+	RETR_T1 << 1, 		/* RT_T1_TO_2 */
+	RETR_T1 << 2, 		/* RT_T1_TO_3 */
+	RETR_T2 			/* RT_T2 */
+						/* NR_OF_TIMER_LISTS */
+};
 
 
 void reset_timer_list( struct s_table* hash_table, enum lists list_id)

+ 3 - 0
modules/tm/timer.h

@@ -25,7 +25,10 @@ enum lists
 
 
 #define is_in_timer_list2(_tl) ( (_tl)->timer_list )
+
 extern int timer_group[NR_OF_TIMER_LISTS];
+extern unsigned int timer_id2timeout[NR_OF_TIMER_LISTS];
+
 struct timer;
 
 #include "lock.h"

+ 55 - 111
modules/tm/tm.c

@@ -17,6 +17,8 @@
 #include "sip_msg.h"
 #include "h_table.h"
 #include "t_funcs.h"
+#include "t_hooks.h"
+#include "tm_load.h"
 
 
 
@@ -39,11 +41,6 @@ static int w_t_add_fork_on_no_rpl(struct sip_msg* msg,char* str,char* str2);
 static int w_t_clear_forks(struct sip_msg* msg, char* str, char* str2);
 static void w_onbreak(struct sip_msg* msg) { t_unref(); }
 
-static int w_t_setflag( struct sip_msg* msg, char *flag, char *foo );
-static int w_t_resetflag( struct sip_msg* msg, char *flag, char *foo );
-static int w_t_isflagset( struct sip_msg* msg, char *flag, char *foo );
-static int fixup_t_flag(void** param, int param_no);
-
 static int mod_init(void);
 
 #ifdef STATIC_TM
@@ -51,7 +48,8 @@ struct module_exports tm_exports = {
 #else
 struct module_exports exports= {
 #endif
-	"tm_module",
+	"tm",
+	/* -------- exported functions ----------- */
 	(char*[]){			
 				"t_add_transaction",
 				"t_lookup_request",
@@ -67,9 +65,8 @@ struct module_exports exports= {
 				"t_fork_to_uri",
 				"t_clear_forks",
 				"t_fork_on_no_response",
-				"t_setflag",
-				"t_resetflag",
-				"t_isflagset"
+				"register_tmcb",
+				"load_tm"
 			},
 	(cmd_function[]){
 					w_t_add_transaction,
@@ -86,9 +83,8 @@ struct module_exports exports= {
 					w_t_add_fork_uri,
 					w_t_clear_forks,
 					w_t_add_fork_on_no_rpl,
-					w_t_setflag,
-					w_t_resetflag,
-					w_t_isflagset
+					(cmd_function) register_tmcb,
+					(cmd_function) load_tm
 					},
 	(int[]){
 				0, /* t_add_transaction */
@@ -105,9 +101,8 @@ struct module_exports exports= {
 				1, /* t_fork_to_uri */
 				0, /* t_clear_forks */
 				1,  /* t_add_fork_on_no_response */
-				1, /* t_setflag */
-				1, /* t_resetflag */
-				1 /* w_t_isflagset */
+				2 /* register_tmcb */,
+				1 /* load_tm */
 			},
 	(fixup_function[]){
 				0,						/* t_add_transaction */
@@ -124,16 +119,45 @@ struct module_exports exports= {
 				fixup_t_add_fork_uri,   /* t_fork_to_uri */
 				0,						/* t_clear_forks */
 				fixup_t_add_fork_uri,	/* t_add_fork_on_no_response */
-				fixup_t_flag,			/* t_setflag */
-				fixup_t_flag,			/* t_resetflag */
-				fixup_t_flag			/* t_isflagset */
+				0,						/* register_tmcb */
+				0						/* load_tm */
 	
 		},
-	17,
-	NULL,   /* Module parameter names */
-	NULL,   /* Module parameter types */
-	NULL,   /* Module parameter variable pointers */
-	0,      /* Number of module paramers */
+	16,
+
+	/* ------------ exported variables ---------- */
+	(char *[]) { /* Module parameter names */
+		"fr_timer",
+		"fr_inv_timer",
+		"wt_timer",
+		"delete_timer",
+		"retr_timer1p1",
+		"retr_timer1p2",
+		"retr_timer1p3",
+		"retr_timer2"
+	},
+	(modparam_t[]) { /* variable types */
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM,
+		INT_PARAM
+	},
+	(void *[]) { /* variable pointers */
+		&(timer_id2timeout[FR_TIMER_LIST]),
+		&(timer_id2timeout[FR_INV_TIMER_LIST]),
+		&(timer_id2timeout[WT_TIMER_LIST]),
+		&(timer_id2timeout[DELETE_LIST]),
+		&(timer_id2timeout[RT_T1_TO_1]),
+		&(timer_id2timeout[RT_T1_TO_2]),
+		&(timer_id2timeout[RT_T1_TO_3]),
+		&(timer_id2timeout[RT_T2])
+	},
+	8,      /* Number of module paramers */
+
 	mod_init, /* module initialization function */
 	(response_function) t_on_reply,
 	(destroy_function) tm_shutdown,
@@ -405,8 +429,13 @@ static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
 			ret = 0;
 			break;
 		case AIN_RETR:		/* it's a retransmission */
-			if ( !t_retransmit_reply( p_msg ) )
-				DBG( "SER: WARNING: bad t_retransmit_reply\n");
+			ret=t_retransmit_reply( p_msg );
+			/* look at ret for better debugging output ... */
+			if (ret>0) DBG("DEBUG: reply retransmitted (status %d)\n", ret);
+			else if (ret==-1) DBG("DEBUG: no reply to retransmit; "
+				"probably a non-INVITE transaction which was not replied\n");
+			else LOG(L_ERR, "ERROR: reply retranmission failed\n");
+			/* eventually, do not worry and proceed whatever happened to you...*/
 			ret = 1;
 			break;
 		case AIN_NEW:		/* it's a new request */
@@ -456,6 +485,7 @@ static int t_relay_to( struct sip_msg  *p_msg , char *str_ip , char *str_port)
 			ret = 1;
 			break;
 		case AIN_RTRACK:	/* ACK retransmission */
+			DBG( "SER: ACK retransmission\n");
 			ret = 1;
 			break;
 		default:
@@ -493,89 +523,3 @@ static int t_relay( struct sip_msg  *p_msg , char* foo, char* bar)
 
 
 
-/* wrapping functions for flaf processing  */
-
-static int fixup_t_flag(void** param, int param_no)
-{
-    unsigned int *code;
-	char *c;
-
-	DBG("TM module: fixing flag: %s\n", (char *) (*param));
-
-	if (param_no!=1) {
-		LOG(L_ERR, "ERROR: TM module: only parameter #1 for flags can be fixed\n");
-		return E_BUG;
-	};
-
-	if ( !(code = malloc( sizeof( unsigned int) )) ) return E_OUT_OF_MEM;
-
-	*code = 0;
-	c = *param;
-	while ( *c && (*c==' ' || *c=='\t')) c++; /* intial whitespaces */
-
-	if (strcasecmp(c, "white")==0) *code=FL_WHITE;
-	else if (strcasecmp(c, "yellow")==0) *code=FL_YELLOW;
-	else if (strcasecmp(c, "green")==0) *code=FL_GREEN;
-	else if (strcasecmp(c, "red")==0) *code=FL_RED;
-	else if (strcasecmp(c, "blue")==0) *code=FL_BLUE;
-	else if (strcasecmp(c, "magenta")==0) *code=FL_MAGENTA;
-	else if (strcasecmp(c, "brown")==0) *code=FL_BROWN;
-	else if (strcasecmp(c, "black")==0) *code=FL_BLACK;
-	else while ( *c && *c>='0' && *c<='9' ) {
-		*code = *code*10+ *c-'0';
-		if (*code > (sizeof( tflags_t ) * CHAR_BIT - 1 )) {
-			LOG(L_ERR, "ERROR: TM module: too big flag number: %s; MAX=%d\n",
-				(char *) (*param), sizeof( tflags_t ) * CHAR_BIT - 1 );
-			goto error;
-		}
-		c++;
-	}
-	while ( *c && (*c==' ' || *c=='\t')) c++; /* terminating whitespaces */
-
-	if ( *code == 0 ) {
-		LOG(L_ERR, "ERROR: TM module: bad flag number: %s\n", (char *) (*param));
-		goto error;
-	}
-
-	/* free string */
-	free( *param );
-	/* fix now */
-	*param = code;
-	
-	return 0;
-
-error:
-	free( code );
-	return E_CFG;
-}
-
-
-static int w_t_setflag( struct sip_msg* msg, char *flag, char *foo )
-{
-    if (t_check( msg , 0 , 0)==-1) return -1;
-    if (!T) {
-        DBG("DEBUG: t_setflag: no transaction found\n");
-        return -1;
-    }
-	return t_setflag( (unsigned int) flag );
-}
-
-static int w_t_resetflag( struct sip_msg* msg, char *flag, char *foo )
-{
-    if (t_check( msg , 0 , 0)==-1) return -1;
-    if (!T) {
-        DBG("DEBUG: t_resetflag: no transaction found\n");
-        return -1;
-    }
-	return t_resetflag( (unsigned int) flag );
-}
-
-static int w_t_isflagset( struct sip_msg* msg, char *flag, char *foo )
-{
-    if (t_check( msg , 0 , 0)==-1) return -1;
-    if (!T) {
-        DBG("DEBUG: t_isflagset: no transaction found\n");
-        return -1;
-    }
-	return t_isflagset( (unsigned int) flag );
-}

+ 33 - 0
modules/tm/tm_load.c

@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ */
+
+#include "tm_load.h"
+
+int load_tm( struct tm_binds *tmb)
+{
+	if (!( tmb->register_tmcb=(register_tmcb_f) find_export("register_tmcb", 2)) ) {
+		LOG(L_ERR, "ERROR: tm_bind: TM module function 'register_tmcb' not found\n");
+		return -1;
+	}
+
+	if (!( tmb->t_relay_to=find_export("t_relay_to", 2)) ) {
+		LOG(L_ERR, "ERROR: tm_bind: TM module function 't_relay_to' not found\n");
+		return -1;
+	}
+	if (!( tmb->t_relay=find_export("t_relay", 0)) ) {
+		LOG(L_ERR, "ERROR: tm_bind: TM module function 't_relay' not found\n");
+		return -1;
+	}
+	if (!( tmb->t_fork_to_uri=find_export("t_fork_to_uri", 1)) ) {
+		LOG(L_ERR, "ERROR: tm_bind: TM module function 't_fork_to_uri' not found\n");
+		return -1;
+	}
+	if (!( tmb->t_fork_on_no_response=find_export("t_fork_on_no_response", 1)) ) {
+		LOG(L_ERR, "ERROR: tm_bind: TM module function 't_fork_on_no_response' not found\n");
+		return -1;
+	}
+
+	return 1;
+
+}

+ 31 - 0
modules/tm/tm_load.h

@@ -0,0 +1,31 @@
+/*
+ * $Id$
+ */
+
+#ifndef _TM_BIND_H
+#define _TM_BIND_H
+
+#include "../../sr_module.h"
+#include "t_hooks.h"
+
+struct tm_binds {
+	register_tmcb_f	register_tmcb;
+
+/*
+	cmd_function	t_isflagset;
+	cmd_function	t_setflag;
+	cmd_function	t_resetflag;
+*/
+
+	cmd_function	t_relay_to;
+	cmd_function 	t_relay;
+	cmd_function	t_fork_to_uri;
+	cmd_function	t_fork_on_no_response;
+};
+
+
+typedef int(*load_tm_f)( struct tm_binds *tmb );
+int load_tm( struct tm_binds *tmb);
+
+
+#endif

+ 1 - 1
msg_translator.h

@@ -8,7 +8,7 @@
 #define MY_HF_SEP ": "
 #define MY_HF_SEP_LEN 2
 
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 
 char * build_req_buf_from_sip_req (	struct sip_msg* msg, 
 				unsigned int *returned_len);

+ 5 - 5
msg_parser.c → parser/msg_parser.c

@@ -10,11 +10,11 @@
 
 #include "msg_parser.h"
 #include "parser_f.h"
-#include "ut.h"
-#include "error.h"
-#include "dprint.h"
-#include "data_lump_rpl.h"
-#include "mem/mem.h"
+#include "../ut.h"
+#include "../error.h"
+#include "../dprint.h"
+#include "../data_lump_rpl.h"
+#include "../mem/mem.h"
 
 #ifdef DEBUG_DMALLOC
 #include <mem/dmalloc.h>

+ 8 - 2
msg_parser.h → parser/msg_parser.h

@@ -5,8 +5,9 @@
 #ifndef msg_parser_h
 #define msg_parser_h
 
-#include "str.h"
-#include "data_lump.h"
+#include "../str.h"
+#include "../data_lump.h"
+#include "../flags.h"
 
 #define SIP_REQUEST 1
 #define SIP_REPLY   2
@@ -216,6 +217,11 @@ struct sip_msg{
 	/* index to TM hash table; stored in core to avoid unnecessary calcs */
 	unsigned int  hash_index;
 
+	/* allows to set various flags on the message; may be used for 
+	   simple inter-module communication or remembering processing state
+	   reached */
+	flag_t flags;
+
 	
 };
 

+ 1 - 1
parse_fline.c → parser/parse_fline.c

@@ -7,7 +7,7 @@
 
 
 
-#include "dprint.h"
+#include "../dprint.h"
 #include "msg_parser.h"
 
 

+ 1 - 1
parse_hname.c → parser/parse_hname.c

@@ -17,7 +17,7 @@
 
 
 #include "msg_parser.h"
-#include "dprint.h"
+#include "../dprint.h"
 
 enum { INITIAL=0,
 		VIA1, VIA2,

+ 743 - 0
parser/parse_hname2.c

@@ -0,0 +1,743 @@
+/*
+ * $Id$
+ */
+
+/* 
+ * TODO: Optimize short variants of headers
+ *       Test, Test, Test....
+ *       Hardwire into ser core
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "msg_parser.h"
+#include "../strs.h"
+#include "../dprint.h"
+
+/*
+ * Size of hash table, this is magic value
+ * that ensures, that there are no synonyms for
+ * frequently used keys (frequently used keys are
+ * 4-byte parts of message headers we recognize)
+ * WARNING ! This value MUST be recalculated if you want
+ * a new header to be recognized
+ */
+#define HASH_TABLE_SIZE 1471
+
+
+
+
+/*
+ * Hash function
+ */
+#define HASH_FUNC(val) ((val) % HASH_TABLE_SIZE)
+
+
+/*
+ * This constants marks empty hash table element
+ */
+#define HASH_EMPTY 0x2d2d2d2d
+
+
+/*
+ * Hash table entry
+ */
+struct ht_entry {
+	unsigned int key;
+	unsigned int value;
+};
+
+/*
+hash_table = (struct ht_entry*)malloc(HASH_TABLE_SIZE 
+	* sizeof(struct ht_entry));
+*/
+
+static struct ht_entry hash_table[ HASH_TABLE_SIZE ];
+
+/*
+ * Pointer to the hash table
+ */
+/*
+static struct ht_entry *hash_table;
+*/
+
+
+/*
+ * Declarations
+ */
+static inline char* q_memchr    (char* p, int c, unsigned int size);
+static inline char* skip_ws     (char* p, unsigned int size);
+void         init_htable (void);
+static void         set_entry   (unsigned int key, unsigned int val);
+static inline int   unify       (int key);
+
+/*
+ * Fast replacement of standard memchr function
+ */
+static inline char* q_memchr(char* p, int c, unsigned int size)
+{
+	char* end;
+
+	end=p+size;
+	for(;p<end;p++){
+		if (*p==(unsigned char)c) return p;
+	}
+	return 0;
+}
+
+
+/*
+ * Skip all whitechars and return position of the first
+ * non-white char
+ */
+static inline char* skip_ws(char* p, unsigned int size)
+{
+	char* end;
+	
+	end = p + size;
+	for(; p < end; p++) {
+		if ((*p != ' ') && (*p != '\t')) return p;
+	}
+	return p;
+}
+	
+
+/*
+ * Used to initialize hash table
+ */
+static void set_entry(unsigned int key, unsigned int val)
+{
+	hash_table[HASH_FUNC(key)].key = key;
+	hash_table[HASH_FUNC(key)].value = val;
+}
+
+
+/*
+ * cSeQ -> CSeq and so on...
+ */ 
+static inline int unify(int key)
+{
+	register struct ht_entry* en;
+
+	en = &hash_table[HASH_FUNC(key)];
+	if (en->key == key) {
+		return en->value;
+	} else {
+		return key;
+	}
+}
+
+
+#define Via1_CASE         \
+     hdr->type = HDR_VIA; \
+     hdr->name.len = 3;   \
+     *(p + 3) = '\0';     \
+     return p + 4        
+
+
+#define From_CASE          \
+     hdr->type = HDR_FROM; \
+     p += 4;               \
+     goto dc_end          
+                                                             
+
+#define To12_CASE        \
+     hdr->type = HDR_TO; \
+     hdr->name.len = 2;  \
+     *(p + 2) = '\0';    \
+     return (p + 3)
+
+
+#define CSeq_CASE          \
+     hdr->type = HDR_CSEQ; \
+     p += 4;               \
+     goto dc_end
+
+
+#define Call_CASE                      \
+     p += 4;                           \
+     val = READ(p);                    \
+     switch(val) {                     \
+     case _ID1:                        \
+	     hdr->type = HDR_CALLID;   \
+	     hdr->name.len = 7;        \
+	     *(p + 3) = '\0';          \
+	     return (p + 4);           \
+	                               \
+     case _ID2:                        \
+	     hdr->type = HDR_CALLID;   \
+	     p += 4;                   \
+	     goto dc_end;              \
+     }                                 \
+                                       \
+     val = unify(val);                 \
+     switch(val) {                     \
+     case _ID1:                        \
+	     hdr->type = HDR_CALLID;   \
+	     hdr->name.len = 7;        \
+	     *(p + 3) = '\0';          \
+	     return (p + 4);           \
+	                               \
+     case _ID2:                        \
+	     hdr->type = HDR_CALLID;   \
+	     p += 4;                   \
+	     goto dc_end;              \
+                                       \
+     default: goto other;              \
+     }                                 \
+     break
+
+
+#define Cont_CASE                     \
+     p += 4;                          \
+     val = READ(p);                   \
+     switch(val) {                    \
+     case act1:                       \
+	     hdr->type = HDR_CONTACT; \
+	     hdr->name.len = 7;       \
+	     *(p + 3) = '\0';         \
+	     return (p + 4);          \
+	                              \
+     case act2:                       \
+	     hdr->type = HDR_CONTACT; \
+	     p += 4;                  \
+	     goto dc_end;             \
+     }                                \
+                                      \
+     val = unify(val);                \
+     switch(val) {                    \
+     case act1:                       \
+	     hdr->type = HDR_CONTACT; \
+	     hdr->name.len = 7;       \
+	     *(p + 3) = '\0';         \
+	     return (p + 4);          \
+	                              \
+     case act2:                       \
+	     hdr->type = HDR_CONTACT; \
+	     p += 4;                  \
+	     goto dc_end;             \
+                                      \
+     default: goto other;             \
+     }                                \
+     break
+
+
+#define Rout_CASE                   \
+     p += 4;                        \
+     switch(*p) {                   \
+     case 'e':                      \
+     case 'E':                      \
+	     hdr->type = HDR_ROUTE; \
+	     p++;                   \
+	     goto dc_end;           \
+                                    \
+     default:                       \
+	     goto other;            \
+     }                              \
+     break
+
+
+#define Max_CASE                                   \
+     p += 4;                                       \
+     val = READ(p);                                \
+     switch(val) {                                 \
+     case Forw:                                    \
+	     p += 4;                               \
+	     val = READ(p);                        \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+                                                   \
+	     val = unify(val);                     \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+	     goto other;                           \
+     }                                             \
+                                                   \
+     val = unify(val);                             \
+     switch(val) {                                 \
+     case Forw:                                    \
+	     p += 4;                               \
+	     val = READ(p);                        \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+                                                   \
+	     val = unify(val);                     \
+	     if (val == ards) {                    \
+		     hdr->type = HDR_MAXFORWARDS;  \
+		     p += 4;                       \
+		     goto dc_end;                  \
+	     }                                     \
+     default: goto other;                          \
+     }                                             \
+                                                   \
+     break
+
+
+#define Reco_CASE                                 \
+     p += 4;                                      \
+     val = READ(p);                               \
+     switch(val) {                                \
+     case rd_R:                                   \
+	     p += 4;                              \
+	     val = READ(p);                       \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+                                                  \
+	     val = unify(val);                    \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+	     goto other;                          \
+     }                                            \
+                                                  \
+     val = unify(val);                            \
+     switch(val) {                                \
+     case rd_R:                                   \
+	     p += 4;                              \
+	     val = READ(p);                       \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+                                                  \
+	     val = unify(val);                    \
+	     if (val == oute) {                   \
+		     hdr->type = HDR_RECORDROUTE; \
+		     p += 4;                      \
+		     goto dc_end;                 \
+	     }                                    \
+     default: goto other;                         \
+     }                                            \
+     break
+
+
+#define Via2_CASE         \
+     hdr->type = HDR_VIA; \
+     p += 4;              \
+     goto dc_end
+
+
+#define READ(val) \
+(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
+
+/*
+ * Yet another parse_hname - Ultra Fast version :-)
+ */
+char* parse_hname2(char* begin, char* end, struct hdr_field* hdr)
+{
+	register char* p;
+	register int val;
+
+	p = begin;
+	val = READ(p);
+	hdr->name.s = begin;
+
+	if ((end - begin) < 4) {
+		hdr->type = HDR_ERROR;
+		return begin;
+	}
+
+	switch(val) {
+	case Via1: Via1_CASE;
+	case From: From_CASE;
+	case To12: To12_CASE;
+	case CSeq: CSeq_CASE;
+	case Call: Call_CASE;
+	case Cont: Cont_CASE;
+	case Rout: Rout_CASE;
+	case Max_: Max_CASE;
+	case Reco: Reco_CASE;
+        case Via2: Via2_CASE;
+
+	default:
+		switch(*p) {
+		case 'T':
+		case 't':
+			switch(*(p + 1)) {
+			case 'o':
+			case 'O':
+			case ' ':   /* Short form */
+				hdr->type = HDR_TO;
+				p += 2;
+				goto dc_end;
+
+			case ':':
+				hdr->type = HDR_TO;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+
+		case 'V':
+		case 'v':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_VIA;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_VIA;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'F':
+		case 'f':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_FROM;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_FROM;
+				hdr->name.len = 1;
+				*(p + 1)= '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'I':
+		case 'i':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_CALLID;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_CALLID;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+
+		case 'M':
+		case 'm':
+			switch(*(p + 1)) {
+			case ' ':
+				hdr->type = HDR_CONTACT;
+				p += 2;
+				goto dc_end;
+				
+			case ':':
+				hdr->type = HDR_CONTACT;
+				hdr->name.len = 1;
+				*(p + 1) = '\0';
+				return (p + 2);
+			}
+			break;
+		}
+		
+		val = unify(val);
+		switch(val) {
+		case Via1: Via1_CASE;
+		case From: From_CASE;
+		case To12: To12_CASE;
+		case CSeq: CSeq_CASE;                                                             
+		case Call: Call_CASE;
+		case Cont: Cont_CASE;
+		case Rout: Rout_CASE;                                                             
+		case Max_: Max_CASE;
+		case Reco: Reco_CASE;
+		case Via2: Via2_CASE;
+		default: goto other;
+		}
+        }
+
+	     /* Double colon hasn't been found yet */
+ dc_end:
+       	p = skip_ws(p, end - p);
+	if (*p != ':') {   
+	        goto other;
+	} else {
+		hdr->name.len = p - hdr->name.s;
+		*p = '\0';
+		return (p + 1);
+	}
+
+	     /* Unknown header type */
+ other:    
+	p = q_memchr(p, ':', end - p);
+	if (!p) {        /* No double colon found, error.. */
+		hdr->type = HDR_ERROR;
+		hdr->name.s = NULL;
+		hdr->name.len = 0;
+		return NULL;
+	} else {
+		hdr->type = HDR_OTHER;
+		*p = '\0';
+		hdr->name.len = p - hdr->name.s;
+		return (p + 1);
+	}
+}
+
+
+void init_htable(void)
+{
+	int i;
+
+	     /*
+	      * Create hash table array
+	      */
+
+/*
+	hash_table = (struct ht_entry*)malloc(HASH_TABLE_SIZE * sizeof(struct ht_entry));
+
+*/
+	     /*
+	      * Mark all elements as empty
+	      */
+	for(i = 0; i < HASH_TABLE_SIZE; i++) {
+		set_entry(HASH_EMPTY, HASH_EMPTY);
+	}
+
+        set_entry(via1, Via1);
+	set_entry(viA1, Via1);
+	set_entry(vIa1, Via1);
+        set_entry(vIA1, Via1);
+        set_entry(Via1, Via1);
+        set_entry(ViA1, Via1);
+	set_entry(VIa1, Via1);
+	set_entry(VIA1, Via1);
+	
+        set_entry(via2, Via2);
+	set_entry(viA2, Via2);
+	set_entry(vIa2, Via2);
+	set_entry(vIA2, Via2);
+	set_entry(Via2, Via2);
+	set_entry(ViA2, Via2);
+	set_entry(VIa2, Via2);
+	set_entry(VIA2, Via2);
+	
+	set_entry(from, From);
+	set_entry(froM, From);
+	set_entry(frOm, From);
+	set_entry(frOM, From);
+	set_entry(fRom, From);
+	set_entry(fRoM, From);
+	set_entry(fROm, From);
+	set_entry(fROM, From);
+	set_entry(From, From);
+	set_entry(FroM, From);
+	set_entry(FrOm, From);
+	set_entry(FrOM, From);
+	set_entry(FRom, From);
+	set_entry(FRoM, From);
+	set_entry(FROm, From);
+	set_entry(FROM, From);
+	
+	set_entry(to12, To12);
+	set_entry(tO12, To12);
+	set_entry(To12, To12);
+	set_entry(TO12, To12);
+
+	set_entry(to21, To21);
+	set_entry(tO21, To21);
+	set_entry(To21, To21);
+	set_entry(TO21, To21);
+
+	set_entry(cseq, CSeq);
+	set_entry(cseQ, CSeq);
+	set_entry(csEq, CSeq);
+	set_entry(csEQ, CSeq);
+	set_entry(cSeq, CSeq);
+	set_entry(cSeQ, CSeq);
+	set_entry(cSEq, CSeq);
+	set_entry(cSEQ, CSeq);
+	set_entry(Cseq, CSeq);
+	set_entry(CseQ, CSeq);
+	set_entry(CsEq, CSeq);
+	set_entry(CsEQ, CSeq);
+	set_entry(CSeq, CSeq);
+	set_entry(CSeQ, CSeq);
+	set_entry(CSEq, CSeq);
+	set_entry(CSEQ, CSeq);
+	
+	set_entry(call, Call);
+	set_entry(calL, Call);
+	set_entry(caLl, Call);
+	set_entry(caLL, Call);
+	set_entry(cAll, Call);
+	set_entry(cAlL, Call);
+	set_entry(cALl, Call);
+	set_entry(cALL, Call);
+	set_entry(Call, Call);
+	set_entry(CalL, Call);
+	set_entry(CaLl, Call);
+	set_entry(CaLL, Call);
+	set_entry(CAll, Call);
+	set_entry(CAlL, Call);
+	set_entry(CALl, Call);
+	set_entry(CALL, Call);
+
+	set_entry(_id1, _ID1);
+	set_entry(_iD1, _ID1);
+	set_entry(_Id1, _ID1);
+	set_entry(_ID1, _ID1);
+
+	set_entry(_id2, _ID2);
+	set_entry(_iD2, _ID2);
+	set_entry(_Id2, _ID2);
+	set_entry(_ID2, _ID2);
+
+	set_entry(cont, Cont);
+	set_entry(conT, Cont);
+	set_entry(coNt, Cont);
+	set_entry(coNT, Cont);
+	set_entry(cOnt, Cont);
+	set_entry(cOnT, Cont);
+	set_entry(cONt, Cont);
+	set_entry(cONT, Cont);
+	set_entry(Cont, Cont);
+	set_entry(ConT, Cont);
+	set_entry(CoNt, Cont);
+	set_entry(CoNT, Cont);
+	set_entry(COnt, Cont);
+	set_entry(COnT, Cont);
+	set_entry(CONt, Cont);
+	set_entry(CONT, Cont);
+
+	set_entry(act1, act1);
+	set_entry(acT1, act1);
+	set_entry(aCt1, act1);
+	set_entry(aCT1, act1);
+	set_entry(Act1, act1);
+	set_entry(AcT1, act1);
+	set_entry(ACt1, act1);
+	set_entry(ACT1, act1);
+
+	set_entry(act2, act2);
+	set_entry(acT2, act2);
+	set_entry(aCt2, act2);
+	set_entry(aCT2, act2);
+	set_entry(Act2, act2);
+	set_entry(AcT2, act2);
+	set_entry(ACt2, act2);
+	set_entry(ACT2, act2);
+
+	set_entry(max_, Max_);
+	set_entry(maX_, Max_);
+	set_entry(mAx_, Max_);
+	set_entry(mAX_, Max_);
+	set_entry(Max_, Max_);
+	set_entry(MaX_, Max_);
+	set_entry(MAx_, Max_);
+	set_entry(MAX_, Max_);
+
+	set_entry(forw, Forw);
+	set_entry(forW, Forw);
+	set_entry(foRw, Forw);
+	set_entry(foRW, Forw);
+	set_entry(fOrw, Forw);
+	set_entry(fOrW, Forw);
+	set_entry(fORw, Forw);
+	set_entry(fORW, Forw);
+	set_entry(Forw, Forw);
+	set_entry(ForW, Forw);
+	set_entry(FoRw, Forw);
+	set_entry(FoRW, Forw);
+	set_entry(FOrw, Forw);
+	set_entry(FOrW, Forw);
+	set_entry(FORw, Forw);
+	set_entry(FORW, Forw);
+
+	set_entry(ards, ards);
+	set_entry(ardS, ards);
+	set_entry(arDs, ards);
+	set_entry(arDS, ards);
+	set_entry(aRds, ards);
+	set_entry(aRdS, ards);
+	set_entry(aRDs, ards);
+	set_entry(aRDS, ards);
+	set_entry(Ards, ards);
+	set_entry(ArdS, ards);
+	set_entry(ArDs, ards);
+	set_entry(ArDS, ards);
+	set_entry(ARds, ards);
+	set_entry(ARdS, ards);
+	set_entry(ARDs, ards);
+	set_entry(ARDS, ards);
+
+	set_entry(rout, Rout);
+	set_entry(rouT, Rout);
+	set_entry(roUt, Rout);
+	set_entry(roUT, Rout);
+	set_entry(rOut, Rout);
+	set_entry(rOuT, Rout);
+	set_entry(rOUt, Rout);
+	set_entry(rOUT, Rout);
+	set_entry(Rout, Rout);
+	set_entry(RouT, Rout);
+	set_entry(RoUt, Rout);
+	set_entry(RoUT, Rout);
+	set_entry(ROut, Rout);
+	set_entry(ROuT, Rout);
+	set_entry(ROUt, Rout);
+	set_entry(ROUT, Rout);
+
+	set_entry(reco, Reco);
+	set_entry(recO, Reco);
+	set_entry(reCo, Reco);
+	set_entry(reCO, Reco);
+	set_entry(rEco, Reco);
+	set_entry(rEcO, Reco);
+	set_entry(rECo, Reco);
+	set_entry(rECO, Reco);
+	set_entry(Reco, Reco);
+	set_entry(RecO, Reco);
+	set_entry(ReCo, Reco);
+	set_entry(ReCO, Reco);
+	set_entry(REco, Reco);
+	set_entry(REcO, Reco);
+	set_entry(RECo, Reco);
+	set_entry(RECO, Reco);
+
+	set_entry(rd_r, rd_R);
+	set_entry(rd_R, rd_R);
+	set_entry(rD_r, rd_R);
+	set_entry(rD_R, rd_R);
+	set_entry(Rd_r, rd_R);
+	set_entry(Rd_R, rd_R);
+	set_entry(RD_r, rd_R);
+	set_entry(RD_R, rd_R);
+
+	set_entry(oute, oute);
+	set_entry(outE, oute);
+	set_entry(ouTe, oute);
+	set_entry(ouTE, oute);
+	set_entry(oUte, oute);
+	set_entry(oUtE, oute);
+	set_entry(oUTe, oute);
+	set_entry(oUTE, oute);
+	set_entry(Oute, oute);
+	set_entry(OutE, oute);
+	set_entry(OuTe, oute);
+	set_entry(OuTE, oute);
+	set_entry(OUte, oute);
+	set_entry(OUtE, oute);
+	set_entry(OUTe, oute);
+	set_entry(OUTE, oute);
+}
+
+

+ 3 - 3
parse_to.c → parser/parse_to.c

@@ -2,10 +2,10 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include "dprint.h"
+#include "../dprint.h"
 #include "msg_parser.h"
-#include "ut.h"
-#include "mem/mem.h"
+#include "../ut.h"
+#include "../mem/mem.h"
 
 
 enum{ START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN

+ 3 - 3
parse_via.c → parser/parse_via.c

@@ -19,10 +19,10 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include "dprint.h"
+#include "../dprint.h"
 #include "msg_parser.h"
-#include "ut.h"
-#include "mem/mem.h"
+#include "../ut.h"
+#include "../mem/mem.h"
 
 
 

+ 1 - 1
parser_f.c → parser/parser_f.c

@@ -6,7 +6,7 @@
  */
 
 #include  "parser_f.h"
-#include "ut.h"
+#include "../ut.h"
 
 /* returns pointer to next line or after the end of buffer */
 char* eat_line(char* buffer, unsigned int len)

+ 0 - 0
parser_f.h → parser/parser_f.h


+ 1 - 1
receive.c

@@ -9,7 +9,7 @@
 #include "receive.h"
 #include "dprint.h"
 #include "route.h"
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 #include "forward.h"
 #include "action.h"
 #include "mem/mem.h"

+ 1 - 1
route.h

@@ -12,7 +12,7 @@
 #include "config.h"
 #include "error.h"
 #include "route_struct.h"
-#include "msg_parser.h"
+#include "parser/msg_parser.h"
 
 /*#include "cfg_parser.h" */
 

+ 2 - 1
route_struct.h

@@ -26,7 +26,8 @@ enum { METHOD_O=1, URI_O, SRCIP_O, DSTIP_O, DEFAULT_O, ACTION_O, NUMBER_O};
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 
-		SET_PORT_T, SET_URI_T, IF_T, MODULE_T };
+		SET_PORT_T, SET_URI_T, IF_T, MODULE_T,
+		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T };
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
 		EXPR_ST, ACTIONS_ST, CMDF_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST };
 

+ 1 - 1
sr_module.h

@@ -7,7 +7,7 @@
 #ifndef sr_module_h
 #define sr_module_h
 
-#include "msg_parser.h" /* for sip_msg */
+#include "parser/msg_parser.h" /* for sip_msg */
 
 typedef  struct module_exports* (*module_register)();
 typedef  int (*cmd_function)(struct sip_msg*, char*, char*);