Browse code

- new route type: error_route - to be automatically executed when an error occured while sip request processing - now it is triggered by parsing errors of r-uri, header structure, From, To, CSeq, Call-ID, Content-Length - new pseudo variables available in error_route - $err.class - the class of error - $err.level - the severity level - $err.info - text describing the error - $err.rcode - recommended reply code - $err.rreason - recommended reply reason - you have to call exit in error_route to stop the execution - sl_reply(code,reason) is similar to sl_send_reply(), but can take pseudo-variables in parameters (sl_send_reply() is kept by now because it is used internally by other modules) - both sl_reply() and sl_send_reply() can be used in error_route - append_to_reply() can be used in error_route

- struct to_body has a new field, parsed_uri to cache the URI in From and To headers (suggeste by Juha Heinanen)
- parse_from_uri() and parse_to_uri() were introduced to parse and return From/To uri
- psuedo-varaibles and several modules were updated to use the cached structure of From and To URI -- lot of re-parsing is avoided now
- cloning of sip uri in tm is done for all members


git-svn-id: https://openser.svn.sourceforge.net/svnroot/openser/trunk@1473 689a6050-402a-0410-94f2-e92a70836424

Daniel-Constantin Mierla authored on 09/01/2007 15:30:28
Showing 23 changed files
... ...
@@ -67,12 +67,6 @@ str   dstrip_s;
67 67
 db_con_t* db_handle;   /* Database connection handle */
68 68
 db_func_t adbf;  /* DB functions */
69 69
 
70
-/*
71
- * sl_send_reply function pointer
72
- */
73
-int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2);
74
-
75
-
76 70
 /* Exported functions */
77 71
 static cmd_export_t cmds[] = {
78 72
 	{"alias_db_lookup", alias_db_lookup, 1, 0, REQUEST_ROUTE|FAILURE_ROUTE},
... ...
@@ -146,18 +140,6 @@ static int mod_init(void)
146 140
 	}
147 141
 		
148 142
 
149
-	/**
150
-	 * We will need sl_send_reply from stateless
151
-	 * module for sending replies
152
-	 */
153
-	
154
-	sl_reply = find_export("sl_send_reply", 2, 0);
155
-	if (!sl_reply)
156
-	{
157
-		LOG(L_ERR, "alias_db: This module requires sl module\n");
158
-		return -1;
159
-	}
160
-
161 143
 	if(domain_prefix==NULL || strlen(domain_prefix)==0)
162 144
 	{
163 145
 		dstrip_s.s   = 0;
... ...
@@ -45,6 +45,4 @@ extern str   dstrip_s;
45 45
 
46 46
 extern db_con_t* db_handle;   /* Database connection handle */
47 47
 
48
-extern int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2);
49
-
50 48
 #endif /* _ALIAS_DB_H_ */
... ...
@@ -44,8 +44,6 @@ extern db_func_t adbf;  /* DB functions */
44 44
 
45 45
 char useruri_buf[MAX_USERURI_SIZE];
46 46
 
47
-static str err_reason = str_init("Server Internal Error");
48
-
49 47
 /**
50 48
  * Rewrite Request-URI
51 49
  */
... ...
@@ -78,15 +76,7 @@ int alias_db_lookup(struct sip_msg* _msg, char* _table, char* _str2)
78 76
 	db_res_t* db_res = NULL;
79 77
 	
80 78
 	if (parse_sip_msg_uri(_msg) < 0)
81
-	{
82
-		LOG(L_ERR, "alias_db_lookup: Error while parsing Request-URI\n");
83
-
84
-		if (sl_reply(_msg, (char*)400, "Bad Request-URI") == -1)
85
-		{
86
-			LOG(L_ERR, "alias_db_lookup: Error while sending reply\n");
87
-		}
88
-		return 0;
89
-	}
79
+		return -1;
90 80
 	
91 81
 	db_vals[0].type = DB_STR;
92 82
 	db_vals[0].nul = 0;
... ...
@@ -208,10 +198,6 @@ int alias_db_lookup(struct sip_msg* _msg, char* _table, char* _str2)
208 198
 	return 1;
209 199
 
210 200
 err_server:
211
-	if (sl_reply(_msg, (char*)(long)500, (char*)&err_reason) == -1)
212
-	{
213
-		LOG(L_ERR, "alias_db_lookup: Error while sending reply\n");
214
-	}
215
-	return 0;
201
+	return -1;
216 202
 }
217 203
 
... ...
@@ -153,7 +153,7 @@ auth_result_t pre_auth(struct sip_msg* _m, str* _realm, hdr_types_t _hftype,
153 153
 {
154 154
 	int ret;
155 155
 	auth_body_t* c;
156
-	struct sip_uri uri;
156
+	struct sip_uri *uri;
157 157
 
158 158
 	/* ACK and CANCEL must be always authorized, there is
159 159
 	 * no way how to challenge ACK and CANCEL cannot be
... ...
@@ -172,7 +172,7 @@ auth_result_t pre_auth(struct sip_msg* _m, str* _realm, hdr_types_t _hftype,
172 172
 			return ERROR;
173 173
 		}
174 174
 		
175
-		*_realm = uri.host;
175
+		*_realm = uri->host;
176 176
 		strip_realm(_realm);
177 177
 	}
178 178
 
... ...
@@ -139,7 +139,7 @@ static inline int challenge(struct sip_msg* _msg, xl_elem_t* _realm, int _qop,
139 139
 	char *auth_hf;
140 140
 	int ret;
141 141
 	hdr_types_t hftype = 0; /* Makes gcc happy */
142
-	struct sip_uri uri;
142
+	struct sip_uri *uri;
143 143
 	str realm;
144 144
 	str reason;
145 145
 
... ...
@@ -166,7 +166,7 @@ static inline int challenge(struct sip_msg* _msg, xl_elem_t* _realm, int _qop,
166 166
 			return 0;
167 167
 		}
168 168
 
169
-		realm = uri.host;
169
+		realm = uri->host;
170 170
 		strip_realm(&realm);
171 171
 	} else {
172 172
 		if(xl_printf_s(_msg, _realm, &realm)!=0) {
... ...
@@ -33,6 +33,7 @@
33 33
 #include <string.h>
34 34
 #include "../../dprint.h"
35 35
 #include "../../parser/parse_from.h"
36
+#include "../../parser/parse_to.h"
36 37
 #include "../../parser/parse_uri.h"
37 38
 #include "../../data_lump_rpl.h"
38 39
 #include "auth_mod.h"
... ...
@@ -42,10 +43,11 @@
42 43
 /* 
43 44
  * Return parsed To or From, host part of the parsed uri is realm
44 45
  */
45
-int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri* _u)
46
+int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u)
46 47
 {
47
-	str uri;
48 48
 
49
+	if(_u==NULL)
50
+		return -1;
49 51
 	if ((REQ_LINE(_m).method.len == 8) 
50 52
 	    && !memcmp(REQ_LINE(_m).method.s, "REGISTER", 8) 
51 53
 	    && (_hftype == HDR_AUTHORIZATION_T)
... ...
@@ -56,19 +58,15 @@ int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri* _u)
56 58
 		}
57 59
 		
58 60
 		/* Body of To header field is parsed automatically */
59
-		uri = get_to(_m)->uri; 
61
+		if((*_u = parse_to_uri(_m))==NULL)
62
+			return -1;
60 63
 	} else {
61 64
 		if (parse_from_header(_m) < 0) {
62 65
 			LOG(L_ERR, "get_realm(): Error while parsing headers\n");
63 66
 			return -2;
64 67
 		}
65
-
66
-		uri = get_from(_m)->uri;
67
-	}
68
-
69
-	if (parse_uri(uri.s, uri.len, _u) < 0) {
70
-		LOG(L_ERR, "get_realm(): Error while parsing URI\n");
71
-		return -3;
68
+		if((*_u = parse_from_uri(_m))==NULL)
69
+			return -1;
72 70
 	}
73 71
 	
74 72
 	return 0;
... ...
@@ -34,7 +34,7 @@
34 34
 /* 
35 35
  * Return parsed To or From, host part of the parsed uri is realm
36 36
  */
37
-int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri* _u);
37
+int get_realm(struct sip_msg* _m, hdr_types_t _hftype, struct sip_uri** _u);
38 38
 
39 39
 
40 40
 /*
... ...
@@ -272,6 +272,7 @@ db_res_t *db_load_avp( str *uuid, str *username, str *domain,
272 272
 
273 273
 void db_close_query( db_res_t *res )
274 274
 {
275
+	DBG("close avp query\n");
275 276
 	avpops_dbf.free_result( db_hdl, res);
276 277
 }
277 278
 
... ...
@@ -341,8 +342,10 @@ int db_query_avp(struct sip_msg *msg, char *query, avpname_list_t* dest)
341 342
 		return 1;
342 343
 	}
343 344
 
345
+	DBG("avpops:db_query_avp: rows [%d]\n", RES_ROW_N(db_res));
344 346
 	for(i = RES_ROW_N(db_res)-1; i >= 0; i--) 
345 347
 	{
348
+		DBG("avpops:db_query_avp: row [%d]\n", i);
346 349
 		crt = dest;
347 350
 		for(j = RES_COL_N(db_res)-1; j >= 0; j--) 
348 351
 		{
... ...
@@ -151,22 +151,14 @@ int is_domain_local(str* _host)
151 151
  */
152 152
 int is_from_local(struct sip_msg* _msg, char* _s1, char* _s2)
153 153
 {
154
-	str uri;
155
-	struct sip_uri puri;
154
+	struct sip_uri *puri;
156 155
 
157
-	if (parse_from_header(_msg) < 0) {
156
+	if ((puri=parse_from_uri(_msg))==NULL) {
158 157
 		LOG(L_ERR, "is_from_local(): Error while parsing From header\n");
159 158
 		return -2;
160 159
 	}
161 160
 
162
-	uri = get_from(_msg)->uri;
163
-
164
-	if (parse_uri(uri.s, uri.len, &puri) < 0) {
165
-		LOG(L_ERR, "is_from_local(): Error while parsing URI\n");
166
-		return -3;
167
-	}
168
-
169
-	return is_domain_local(&(puri.host));
161
+	return is_domain_local(&(puri->host));
170 162
 
171 163
 }
172 164
 
... ...
@@ -43,80 +43,29 @@
43 43
 
44 44
 
45 45
 
46
-/*
47
- * Get Request-URI
48
- */
49
-static inline int get_request_uri(struct sip_msg* _m, str* _u)
50
-{
51
-	if (_m->new_uri.s) {
52
-		_u->s = _m->new_uri.s;
53
-		_u->len = _m->new_uri.len;
54
-	} else {
55
-		_u->s = _m->first_line.u.request.uri.s;
56
-		_u->len = _m->first_line.u.request.uri.len;
57
-	}
58
-
59
-	return 0;
60
-}
61
-
62
-
63
-/*
64
- * Get To header field URI
65
- */
66
-static inline int get_to_uri(struct sip_msg* _m, str* _u)
67
-{
68
-	if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0) == -1) || (!_m->to))) {
69
-		LOG(L_ERR, "get_to_uri(): Can't get To header field\n");
70
-		return -1;
71
-	}
72
-	
73
-	_u->s = ((struct to_body*)_m->to->parsed)->uri.s;
74
-	_u->len = ((struct to_body*)_m->to->parsed)->uri.len;
75
-
76
-	return 0;
77
-}
78
-
79
-
80
-/*
81
- * Get From header field URI
82
- */
83
-static inline int get_from_uri(struct sip_msg* _m, str* _u)
84
-{
85
-	if (parse_from_header(_m) < 0) {
86
-		LOG(L_ERR, "get_from_uri(): Error while parsing From body\n");
87
-		return -1;
88
-	}
89
-	
90
-	_u->s = ((struct to_body*)_m->from->parsed)->uri.s;
91
-	_u->len = ((struct to_body*)_m->from->parsed)->uri.len;
92
-
93
-	return 0;
94
-}
95
-
96
-
97 46
 int get_username_domain(struct sip_msg *msg, group_check_p gcp,
98 47
 											str *username, str *domain)
99 48
 {
100 49
 	struct sip_uri puri;
50
+	struct sip_uri *turi;
101 51
 	struct hdr_field* h;
102 52
 	struct auth_body* c = 0; /* Makes gcc happy */
103 53
 	xl_value_t value;
104
-	str uri;
105 54
 
106
-	uri.s = 0;
107
-	uri.len = 0;
55
+	turi = NULL;
108 56
 
109 57
 	switch(gcp->id) {
110 58
 		case 1: /* Request-URI */
111
-			if (get_request_uri( msg, &uri) < 0) {
59
+			if(parse_sip_msg_uri(msg)<0) {
112 60
 				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
113 61
 					"Request-URI\n");
114 62
 				return -1;
115 63
 			}
64
+			turi = &msg->parsed_uri;
116 65
 			break;
117 66
 
118 67
 		case 2: /* To */
119
-			if (get_to_uri( msg, &uri) < 0) {
68
+			if((turi=parse_to_uri(msg))==NULL) {
120 69
 				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
121 70
 					"To URI\n");
122 71
 				return -1;
... ...
@@ -124,7 +73,7 @@ int get_username_domain(struct sip_msg *msg, group_check_p gcp,
124 73
 			break;
125 74
 
126 75
 		case 3: /* From */
127
-			if (get_from_uri( msg, &uri) < 0) {
76
+			if((turi=parse_from_uri(msg))==NULL) {
128 77
 				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
129 78
 					"From URI\n");
130 79
 				return -1;
... ...
@@ -152,20 +101,18 @@ int get_username_domain(struct sip_msg *msg, group_check_p gcp,
152 101
 					" (error in scripts)\n");
153 102
 				return -1;
154 103
 			}
155
-			uri.s = value.rs.s;
156
-			uri.len = value.rs.len;
104
+			if (parse_uri(value.rs.s, value.rs.len, &puri) < 0) {
105
+				LOG(L_ERR, "ERROR:group:get_username_domain: failed to parse "
106
+					"URI <%.*s>\n",value.rs.len, value.rs.s);
107
+				return -1;
108
+			}
109
+			turi = &puri;
157 110
 			break;
158 111
 	}
159 112
 
160 113
 	if (gcp->id != 4) {
161
-		if (parse_uri(uri.s, uri.len, &puri) < 0) {
162
-			LOG(L_ERR, "ERROR:group:get_username_domain: failed to parse "
163
-				"URI <%.*s>\n",uri.len,uri.s);
164
-			return -1;
165
-		}
166
-
167
-		*username = puri.user;
168
-		*domain = puri.host;
114
+		*username = turi->user;
115
+		*domain = turi->host;
169 116
 	} else {
170 117
 		*username = c->digest.username.user;
171 118
 		*domain = *(GET_REALM(&c->digest));
... ...
@@ -43,64 +43,6 @@
43 43
 #include "grouprad_mod.h"
44 44
 
45 45
 
46
-/*
47
- * Get actual Request-URI
48
- */
49
-static inline int get_request_uri(struct sip_msg* _m, str* _u)
50
-{
51
-	     /* Use new_uri if present */
52
-	if (_m->new_uri.s) {
53
-		_u->s = _m->new_uri.s;
54
-		_u->len = _m->new_uri.len;
55
-	} else {
56
-		_u->s = _m->first_line.u.request.uri.s;
57
-		_u->len = _m->first_line.u.request.uri.len;
58
-	}
59
-
60
-	return 0;
61
-}
62
-
63
-
64
-/*
65
- * Get To header field URI
66
- */
67
-static inline int get_to_uri(struct sip_msg* _m, str* _u)
68
-{
69
-	     /* Double check that the header field is there
70
-	      * and is parsed
71
-	      */
72
-	if (!_m->to && ((parse_headers(_m, HDR_TO_F, 0) == -1) || !_m->to)) {
73
-		LOG(L_ERR, "get_to_uri(): Can't get To header field\n");
74
-		return -1;
75
-	}
76
-	
77
-	_u->s = ((struct to_body*)_m->to->parsed)->uri.s;
78
-	_u->len = ((struct to_body*)_m->to->parsed)->uri.len;
79
-	
80
-	return 0;
81
-}
82
-
83
-
84
-/*
85
- * Get From header field URI
86
- */
87
-static inline int get_from_uri(struct sip_msg* _m, str* _u)
88
-{
89
-	     /* Double check that the header field is there
90
-	      * and is parsed
91
-	      */
92
-	if (parse_from_header(_m) < 0) {
93
-		LOG(L_ERR, "get_from_uri(): Error while parsing From body\n");
94
-		return -1;
95
-	}
96
-	
97
-	_u->s = ((struct to_body*)_m->from->parsed)->uri.s;
98
-	_u->len = ((struct to_body*)_m->from->parsed)->uri.len;
99
-
100
-	return 0;
101
-}
102
-
103
-
104 46
 /*
105 47
  * Check from Radius if a user belongs to a group. User-Name is digest
106 48
  * username or digest username@realm, SIP-Group is group, and Service-Type
... ...
@@ -109,65 +51,65 @@ static inline int get_from_uri(struct sip_msg* _m, str* _u)
109 51
  */
110 52
 int radius_is_user_in(struct sip_msg* _m, char* _hf, char* _group)
111 53
 {
112
-	str *grp, user_name, user, domain, uri;
54
+	str *grp, user_name, user, domain;
113 55
 	dig_cred_t* cred = 0;
114 56
 	int hf_type;
115 57
 	UINT4 service;
116 58
 	VALUE_PAIR *send, *received;
117 59
 	static char msg[4096];
118 60
 	struct hdr_field* h;
119
-	struct sip_uri puri;
61
+	struct sip_uri *turi;
120 62
 
121 63
 	grp = (str*)_group; /* via fixup */
122 64
 	send = received = 0;
123 65
 
124 66
 	hf_type = (int)(long)_hf;
125 67
 
126
-	uri.s = 0;
127
-	uri.len = 0;
68
+	turi = 0;
128 69
 
129 70
 	switch(hf_type) {
130
-	case 1: /* Request-URI */
131
-		if (get_request_uri(_m, &uri) < 0) {
132
-			LOG(L_ERR, "radius_is_user_in(): Error while extracting Request-URI\n");
133
-			return -1;
134
-		}
135
-		break;
136
-
137
-	case 2: /* To */
138
-		if (get_to_uri(_m, &uri) < 0) {
139
-			LOG(L_ERR, "radius_is_user_in(): Error while extracting To\n");
140
-			return -2;
141
-		}
142
-		break;
71
+		case 1: /* Request-URI */
72
+			if(parse_sip_msg_uri(_m)<0) {
73
+				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
74
+					"Request-URI\n");
75
+				return -1;
76
+			}
77
+			turi = &_m->parsed_uri;
78
+			break;
79
+
80
+		case 2: /* To */
81
+			if((turi=parse_to_uri(_m))==NULL) {
82
+				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
83
+					"To URI\n");
84
+				return -1;
85
+			}
86
+			break;
143 87
 
144
-	case 3: /* From */
145
-		if (get_from_uri(_m, &uri) < 0) {
146
-			LOG(L_ERR, "radius_is_user_in(): Error while extracting From\n");
147
-			return -3;
148
-		}
149
-		break;
88
+		case 3: /* From */
89
+			if((turi=parse_from_uri(_m))==NULL) {
90
+				LOG(L_ERR, "ERROR:group:get_username_domain: failed to get "
91
+					"From URI\n");
92
+				return -1;
93
+			}
94
+			break;
150 95
 
151
-	case 4: /* Credentials */
152
-		get_authorized_cred(_m->authorization, &h);
153
-		if (!h) {
154
-			get_authorized_cred(_m->proxy_auth, &h);
96
+		case 4: /* Credentials */
97
+			get_authorized_cred(_m->authorization, &h);
155 98
 			if (!h) {
156
-				LOG(L_ERR, "radius_is_user_in(): No authorized credentials found (error in scripts)\n");
157
-				return -4;
99
+				get_authorized_cred(_m->proxy_auth, &h);
100
+				if (!h) {
101
+					LOG(L_ERR, "radius_is_user_in(): No authorized"
102
+							" credentials found (error in scripts)\n");
103
+					return -4;
104
+				}
158 105
 			}
159
-		}
160
-		cred = &((auth_body_t*)(h->parsed))->digest;
161
-		break;
106
+			cred = &((auth_body_t*)(h->parsed))->digest;
107
+			break;
162 108
 	}
163 109
 
164 110
 	if (hf_type != 4) {
165
-		if (parse_uri(uri.s, uri.len, &puri) < 0) {
166
-			LOG(L_ERR, "radius_is_user_in(): Error while parsing URI\n");
167
-			return -5;
168
-		}
169
-		user = puri.user;
170
-		domain = puri.host;
111
+		user = turi->user;
112
+		domain = turi->host;
171 113
 	} else {
172 114
 		user = cred->username.user;
173 115
 		domain = *GET_REALM(cred);
... ...
@@ -29,7 +29,8 @@ Bogdan Iancu
29 29
         1.4. Exported Functions
30 30
 
31 31
               1.4.1. sl_send_reply(code, reason)
32
-              1.4.2. sl_reply_error()
32
+              1.4.2. sl_reply(code, reason)
33
+              1.4.3. sl_reply_error()
33 34
 
34 35
    2. Developer's Guide
35 36
    3. Frequently Asked Questions
... ...
@@ -38,7 +39,8 @@ Bogdan Iancu
38 39
    1-1. enable_stats example
39 40
    1-2. totag_avpid example
40 41
    1-3. sl_send_reply usage
41
-   1-4. sl_reply_error usage
42
+   1-4. sl_send_reply usage
43
+   1-5. sl_reply_error usage
42 44
      _________________________________________________________
43 45
 
44 46
 Chapter 1. User's Guide
... ...
@@ -132,7 +134,7 @@ modparam("sl", "totag_avpid", 25)
132 134
      * code - Return code.
133 135
      * reason - Reason phrase.
134 136
 
135
-   This function can be used from REQUEST_ROUTE.
137
+   This function can be used from REQUEST_ROUTE, ERROR_ROUTE.
136 138
 
137 139
    Example 1-3. sl_send_reply usage
138 140
 ...
... ...
@@ -140,7 +142,29 @@ sl_send_reply("404", "Not found");
140 142
 ...
141 143
      _________________________________________________________
142 144
 
143
-1.4.2. sl_reply_error()
145
+1.4.2. sl_reply(code, reason)
146
+
147
+   For the current request, a reply is sent back having the given
148
+   code and text reason. The reply is sent stateless, totally
149
+   independent of the Transaction module and with no
150
+   retransmission for the INVITE's replies. 'code' and 'reason'
151
+   can contain pseudo-variables that are replaced at runtime. It
152
+   is very useful in conjunction with 'error_route'.
153
+
154
+   Meaning of the parameters is as follows:
155
+
156
+     * code - Return code.
157
+     * reason - Reason phrase.
158
+
159
+   This function can be used from REQUEST_ROUTE, ERROR_ROUTE.
160
+
161
+   Example 1-4. sl_send_reply usage
162
+...
163
+sl_reply("$err.rcode", "$err.rreason");
164
+...
165
+     _________________________________________________________
166
+
167
+1.4.3. sl_reply_error()
144 168
 
145 169
    Sends back an error reply describing the nature of the last
146 170
    internal error. Usually this function should be used after a
... ...
@@ -148,7 +172,7 @@ sl_send_reply("404", "Not found");
148 172
 
149 173
    This function can be used from REQUEST_ROUTE.
150 174
 
151
-   Example 1-4. sl_reply_error usage
175
+   Example 1-5. sl_reply_error usage
152 176
 ...
153 177
 sl_reply_error();
154 178
 ...
... ...
@@ -138,7 +138,7 @@ modparam("sl", "totag_avpid", 25)
138 138
 		</listitem>
139 139
 		</itemizedlist>
140 140
 		<para>
141
-		This function can be used from REQUEST_ROUTE.
141
+		This function can be used from REQUEST_ROUTE, ERROR_ROUTE.
142 142
 		</para>
143 143
 		<example>
144 144
 		<title><function>sl_send_reply</function> usage</title>
... ...
@@ -150,6 +150,42 @@ sl_send_reply("404", "Not found");
150 150
 		</example>
151 151
 	</section>
152 152
 
153
+	<section>
154
+		<title>
155
+		<function moreinfo="none">sl_reply(code, reason)</function>
156
+		</title>
157
+		<para>
158
+		For the current request, a reply is sent back having the given code 
159
+		and text reason. The reply is sent stateless, totally independent of 
160
+		the Transaction module and with no retransmission for the INVITE's 
161
+		replies. 'code' and 'reason' can contain pseudo-variables that are
162
+		replaced at runtime. It is very useful in conjunction with
163
+		'error_route'.
164
+		</para>
165
+		<para>Meaning of the parameters is as follows:</para>
166
+		<itemizedlist>
167
+		<listitem>
168
+			<para><emphasis>code</emphasis> - Return code.
169
+			</para>
170
+		</listitem>
171
+		<listitem>
172
+			<para><emphasis>reason</emphasis> - Reason phrase.
173
+			</para>
174
+		</listitem>
175
+		</itemizedlist>
176
+		<para>
177
+		This function can be used from REQUEST_ROUTE, ERROR_ROUTE.
178
+		</para>
179
+		<example>
180
+		<title><function>sl_send_reply</function> usage</title>
181
+		<programlisting format="linespecific">
182
+...
183
+sl_reply("$err.rcode", "$err.rreason");
184
+...
185
+</programlisting>
186
+		</example>
187
+	</section>
188
+
153 189
 	<section>
154 190
 		<title>
155 191
 		<function moreinfo="none">sl_reply_error()</function>
... ...
@@ -42,15 +42,18 @@
42 42
 #include "../../ut.h"
43 43
 #include "../../script_cb.h"
44 44
 #include "../../mem/mem.h"
45
+#include "../../items.h"
45 46
 #include "sl_funcs.h"
46 47
 #include "sl_cb.h"
47 48
 
48 49
 MODULE_VERSION
49 50
 
50 51
 
51
-static int w_sl_send_reply(struct sip_msg* msg, char* str, char* str2);
52
-static int w_sl_reply_error(struct sip_msg* msg, char* str, char* str2);
52
+static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2);
53
+static int w_sl_reply(struct sip_msg* msg, char* str1, char* str2);
54
+static int w_sl_reply_error(struct sip_msg* msg, char* str1, char* str2);
53 55
 static int fixup_sl_send_reply(void** param, int param_no);
56
+static int fixup_sl_reply(void** param, int param_no);
54 57
 static int mod_init(void);
55 58
 static void mod_destroy();
56 59
 extern int totag_avpid;
... ...
@@ -71,7 +74,9 @@ stat_var *rcv_acks;
71 74
 
72 75
 static cmd_export_t cmds[]={
73 76
 	{"sl_send_reply",   w_sl_send_reply,            2,  fixup_sl_send_reply,
74
-			REQUEST_ROUTE},
77
+			REQUEST_ROUTE | ERROR_ROUTE},
78
+	{"sl_reply",        w_sl_reply,                 2,  fixup_sl_reply,
79
+			REQUEST_ROUTE | ERROR_ROUTE},
75 80
 	{"sl_reply_error",  w_sl_reply_error,           0,  0,
76 81
 			REQUEST_ROUTE},
77 82
 	{"register_slcb",  (cmd_function)register_slcb, 0,  0,
... ...
@@ -193,6 +198,35 @@ static int fixup_sl_send_reply(void** param, int param_no)
193 198
 	return 0;
194 199
 }
195 200
 
201
+static int fixup_sl_reply(void** param, int param_no)
202
+{
203
+	xl_elem_t *model;
204
+	str s;
205
+
206
+	/* convert to str */
207
+	s.s = (char*)*param;
208
+	s.len = strlen(s.s);
209
+
210
+	model=NULL;
211
+	if (param_no==1 || param_no==2)
212
+	{
213
+		if(s.len!=0)
214
+		{
215
+			if(xl_parse_format(s.s,&model,XL_DISABLE_COLORS)<0)
216
+			{
217
+				LOG(L_ERR, "ERROR:sl:fixup_sl_reply: wrong format [%s] "
218
+					"for param no %d!\n", s.s, param_no);
219
+				pkg_free(s.s);
220
+				return E_UNSPEC;
221
+			}
222
+		}
223
+		*param = (void*)model;
224
+	}
225
+
226
+	return 0;
227
+}
228
+
229
+
196 230
 
197 231
 
198 232
 
... ...
@@ -204,9 +238,25 @@ static int w_sl_send_reply(struct sip_msg* msg, char* str1, char* str2)
204 238
 }
205 239
 
206 240
 
207
-static int w_sl_reply_error( struct sip_msg* msg, char* str, char* str2)
241
+static int w_sl_reply_error( struct sip_msg* msg, char* str1, char* str2)
208 242
 {
209 243
 	return sl_reply_error( msg );
210 244
 }
211 245
 
212 246
 
247
+static int w_sl_reply(struct sip_msg* msg, char* str1, char* str2)
248
+{
249
+	str code_s;
250
+	unsigned int code_i;
251
+
252
+	if(str1==NULL || str2==NULL)
253
+		return -1;
254
+	if(xl_printf_s(msg, (xl_elem_p)str1, &code_s)!=0)
255
+		return -1;
256
+	if(str2int(&code_s, &code_i)!=0 || code_i<100)
257
+		return -1;
258
+	if(xl_printf_s(msg, (xl_elem_p)str2, &code_s)!=0 || code_s.len <=0)
259
+		return -1;
260
+	return sl_send_reply(msg, code_i, &code_s);
261
+}
262
+
... ...
@@ -40,8 +40,6 @@
40 40
 
41 41
 #define MAX_USERURI_SIZE	256
42 42
 
43
-static str sd_500_rpl = str_init("Server Internal Error");
44
-static str sd_400_rpl = str_init("Bad Request");
45 43
 
46 44
 char useruri_buf[MAX_USERURI_SIZE];
47 45
 
... ...
@@ -72,7 +70,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _str2)
72 70
 {
73 71
 	str user_s;
74 72
 	int nr_keys;
75
-	struct sip_uri puri;
73
+	struct sip_uri *puri;
76 74
 	db_key_t db_keys[4];
77 75
 	db_val_t db_vals[4];
78 76
 	db_key_t db_cols[1];
... ...
@@ -83,22 +81,17 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _str2)
83 81
 	db_cols[0]=new_uri_column;
84 82
 	
85 83
 	/* take username@domain from From header */
86
-	if ( parse_from_header( _msg )<0 )
84
+	if ( (puri = parse_from_uri(_msg ))==NULL )
87 85
 	{
88 86
 		LOG(L_ERR, "sd_lookup: ERROR cannot parse FROM header\n");
89
-		goto err_badreq;
90
-	}
91
-	if (parse_uri(get_from(_msg)->uri.s, get_from(_msg)->uri.len, &puri) < 0)
92
-	{
93
-		LOG(L_ERR, "sd_lookup: Error while parsing From URI\n");
94
-		goto err_badreq;
87
+		goto err_server;
95 88
 	}
96 89
 		
97 90
 	db_keys[nr_keys]=user_column;
98 91
 	db_vals[nr_keys].type = DB_STR;
99 92
 	db_vals[nr_keys].nul = 0;
100
-	db_vals[nr_keys].val.str_val.s = puri.user.s;
101
-	db_vals[nr_keys].val.str_val.len = puri.user.len;
93
+	db_vals[nr_keys].val.str_val.s = puri->user.s;
94
+	db_vals[nr_keys].val.str_val.len = puri->user.len;
102 95
 	nr_keys++;
103 96
 
104 97
 	if(use_domain>=1)
... ...
@@ -106,13 +99,13 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _str2)
106 99
 		db_keys[nr_keys]=domain_column;
107 100
 		db_vals[nr_keys].type = DB_STR;
108 101
 		db_vals[nr_keys].nul = 0;
109
-		db_vals[nr_keys].val.str_val.s = puri.host.s;
110
-		db_vals[nr_keys].val.str_val.len = puri.host.len;
102
+		db_vals[nr_keys].val.str_val.s = puri->host.s;
103
+		db_vals[nr_keys].val.str_val.len = puri->host.len;
111 104
 		nr_keys++;
112 105
 		
113 106
 		if (dstrip_s.s!=NULL && dstrip_s.len>0
114
-			&& dstrip_s.len<puri.host.len
115
-			&& strncasecmp(puri.host.s,dstrip_s.s,dstrip_s.len)==0)
107
+			&& dstrip_s.len<puri->host.len
108
+			&& strncasecmp(puri->host.s,dstrip_s.s,dstrip_s.len)==0)
116 109
 		{
117 110
 			db_vals[nr_keys].val.str_val.s   += dstrip_s.len;
118 111
 			db_vals[nr_keys].val.str_val.len -= dstrip_s.len;
... ...
@@ -122,7 +115,7 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _str2)
122 115
 	if (parse_sip_msg_uri(_msg) < 0)
123 116
 	{
124 117
 		LOG(L_ERR, "sd_lookup: Error while parsing Request-URI\n");
125
-		goto err_badreq;
118
+		goto err_server;
126 119
 	}
127 120
 	
128 121
 	db_keys[nr_keys]=sd_user_column;
... ...
@@ -221,16 +214,6 @@ int sd_lookup(struct sip_msg* _msg, char* _table, char* _str2)
221 214
 	return 1;
222 215
 
223 216
 err_server:
224
-	if (sl_reply(_msg, (char*)500, (char*)&sd_500_rpl) == -1)
225
-	{
226
-		LOG(L_ERR, "sd_lookup: Error while sending reply\n");
227
-	}
228
-	return 0;
229
-err_badreq:
230
-	if (sl_reply(_msg, (char*)400, (char*)&sd_400_rpl ) == -1)
231
-	{
232
-		LOG(L_ERR, "sd_lookup: Error while sending reply\n");
233
-	}
234
-	return 0;
217
+	return -1;
235 218
 }
236 219
 
... ...
@@ -66,11 +66,6 @@ str   dstrip_s;
66 66
 db_func_t db_funcs;      /* Database functions */
67 67
 db_con_t* db_handle=0;   /* Database connection handle */
68 68
 
69
-/*
70
- * sl_send_reply function pointer
71
- */
72
-int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2);
73
-
74 69
 
75 70
 /* Exported functions */
76 71
 static cmd_export_t cmds[] = {
... ...
@@ -145,18 +140,6 @@ static int mod_init(void)
145 140
 		return -1;
146 141
 	}
147 142
 	
148
-	/**
149
-	 * We will need sl_send_reply from stateless
150
-	 * module for sending replies
151
-	 */
152
-	
153
-	sl_reply = find_export("sl_send_reply", 2, 0);
154
-	if (!sl_reply)
155
-	{
156
-		LOG(L_ERR, "sd: This module requires sl module\n");
157
-		return -1;
158
-	}
159
-
160 143
 	if(domain_prefix==NULL || strlen(domain_prefix)==0)
161 144
 	{
162 145
 		dstrip_s.s   = 0;
... ...
@@ -45,6 +45,4 @@ extern str   dstrip_s;
45 45
 extern db_func_t db_funcs;    /* Database functions */
46 46
 extern db_con_t* db_handle;   /* Database connection handle */
47 47
 
48
-extern int (*sl_reply)(struct sip_msg* _m, char* _s1, char* _s2);
49
-
50 48
 #endif /* _SPEEDDIAL_H_ */
... ...
@@ -394,7 +394,8 @@ if ( subst_body('/^o=(.*) /o=$fU ') ) {};
394 394
 
395 395
      * txt - String which may contains pseudo-variables.
396 396
 
397
-   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE.
397
+   This function can be used from REQUEST_ROUTE, BRANCH_ROUTE,
398
+   ERROR_ROUTE.
398 399
 
399 400
    Example 1-13. append_to_reply usage
400 401
 ...
... ...
@@ -509,7 +509,8 @@ if ( subst_body('/^o=(.*) /o=$fU ') ) {};
509 509
 		</listitem>
510 510
 		</itemizedlist>
511 511
 		<para>
512
-		This function can be used from REQUEST_ROUTE, BRANCH_ROUTE.
512
+		This function can be used from REQUEST_ROUTE, BRANCH_ROUTE,
513
+		ERROR_ROUTE.
513 514
 		</para>
514 515
 		<example>
515 516
 		<title><function>append_to_reply</function> usage</title>
... ...
@@ -139,7 +139,7 @@ static cmd_export_t cmds[]={
139 139
 	{"replace_body_all", replace_body_all_f,2, fixup_regex, 
140 140
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE}, 
141 141
 	{"append_to_reply",  append_to_reply_f, 1, it_list_fixup,
142
-			REQUEST_ROUTE|BRANCH_ROUTE},
142
+			REQUEST_ROUTE|BRANCH_ROUTE|ERROR_ROUTE},
143 143
 	{"append_hf",        append_hf_1,       1, add_header_fixup,
144 144
 			REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
145 145
 	{"append_hf",        append_hf_2,       2, add_header_fixup,
... ...
@@ -181,6 +181,26 @@ static void uri_trans(char *new_buf, char *org_buf, struct sip_uri *uri)
181 181
 	uri->port.s=translate_pointer(new_buf,org_buf,uri->port.s);
182 182
 	uri->params.s=translate_pointer(new_buf,org_buf,uri->params.s);
183 183
 	uri->headers.s=translate_pointer(new_buf,org_buf,uri->headers.s);
184
+	/* parameters */
185
+	uri->transport.s=translate_pointer(new_buf,org_buf,uri->transport.s);
186
+	uri->ttl.s=translate_pointer(new_buf,org_buf,uri->ttl.s);
187
+	uri->user_param.s=translate_pointer(new_buf,org_buf,uri->user_param.s);
188
+	uri->maddr.s=translate_pointer(new_buf,org_buf,uri->maddr.s);
189
+	uri->method.s=translate_pointer(new_buf,org_buf,uri->method.s);
190
+	uri->lr.s=translate_pointer(new_buf,org_buf,uri->lr.s);
191
+	uri->r2.s=translate_pointer(new_buf,org_buf,uri->r2.s);
192
+		/* ser specific rr parameter */
193
+	/* values */
194
+	uri->transport_val.s
195
+		=translate_pointer(new_buf,org_buf,uri->transport_val.s);
196
+	uri->ttl_val.s=translate_pointer(new_buf,org_buf,uri->ttl_val.s);
197
+	uri->user_param_val.s
198
+		=translate_pointer(new_buf,org_buf,uri->user_param_val.s);
199
+	uri->maddr_val.s=translate_pointer(new_buf,org_buf,uri->maddr_val.s);
200
+	uri->method_val.s=translate_pointer(new_buf,org_buf,uri->method_val.s);
201
+	uri->lr_val.s=translate_pointer(new_buf,org_buf,uri->lr_val.s);
202
+		/* lr value placeholder for lr=on a.s.o*/
203
+	uri->r2_val.s=translate_pointer(new_buf,org_buf,uri->r2_val.s);
184 204
 }
185 205
 
186 206
 
... ...
@@ -562,6 +582,11 @@ do { \
562 582
 					((struct to_body*)new_hdr->parsed)->tag_value.s =
563 583
 						translate_pointer( new_msg->buf , org_msg->buf ,
564 584
 						((struct to_body*)hdr->parsed)->tag_value.s );
585
+				if ( (((struct to_body*)hdr->parsed)->parsed_uri.user.s)
586
+				|| (((struct to_body*)hdr->parsed)->parsed_uri.host.s) )
587
+					uri_trans(new_msg->buf, org_msg->buf,
588
+							&((struct to_body*)hdr->parsed)->parsed_uri);
589
+
565 590
 				/*to params*/
566 591
 				to_prm = ((struct to_body*)(hdr->parsed))->param_lst;
567 592
 				for(;to_prm;to_prm=to_prm->next)
... ...
@@ -48,11 +48,10 @@ static db_func_t uridb_dbf;
48 48
  * Check if a header field contains the same username
49 49
  * as digest credentials
50 50
  */
51
-static inline int check_username(struct sip_msg* _m, str* _uri)
51
+static inline int check_username(struct sip_msg* _m, struct sip_uri *_uri)
52 52
 {
53 53
 	struct hdr_field* h;
54 54
 	auth_body_t* c;
55
-	struct sip_uri puri;
56 55
 	db_key_t keys[3];
57 56
 	db_val_t vals[3];
58 57
 	db_key_t cols[1];
... ...
@@ -79,13 +78,8 @@ static inline int check_username(struct sip_msg* _m, str* _uri)
79 78
 	c = (auth_body_t*)(h->parsed);
80 79
 
81 80
 	/* Parse To/From URI */
82
-	if (parse_uri(_uri->s, _uri->len, &puri) < 0) {
83
-		LOG(L_ERR, "check_username(): Error while parsing URI\n");
84
-		return -3;
85
-	}
86
-	
87 81
 	/* Make sure that the URI contains username */
88
-	if (!puri.user.len) {
82
+	if (!_uri->user.len) {
89 83
 		LOG(L_ERR, "check_username(): Username not found in URI\n");
90 84
 		return -4;
91 85
 	}
... ...
@@ -112,7 +106,7 @@ static inline int check_username(struct sip_msg* _m, str* _uri)
112 106
 
113 107
 		VAL_STR(vals) = c->digest.username.user;
114 108
 		VAL_STR(vals + 1) = *GET_REALM(&c->digest);
115
-		VAL_STR(vals + 2) = puri.user;
109
+		VAL_STR(vals + 2) = _uri->user;
116 110
 
117 111
 		if (uridb_dbf.query(db_handle, keys, 0, vals, cols, 3, 1, 0, &res) < 0)
118 112
 		{
... ...
@@ -127,12 +121,12 @@ static inline int check_username(struct sip_msg* _m, str* _uri)
127 121
 		 */
128 122
 		if (RES_ROW_N(res) == 0) {
129 123
 			DBG("check_username(): From/To user '%.*s' is spoofed\n", 
130
-			    puri.user.len, ZSW(puri.user.s));
124
+			    _uri->user.len, ZSW(_uri->user.s));
131 125
 			uridb_dbf.free_result(db_handle, res);
132 126
 			return -9;
133 127
 		} else {
134 128
 			DBG("check_username(): From/To user '%.*s' and auth user match\n", 
135
-			    puri.user.len, ZSW(puri.user.s));
129
+			    _uri->user.len, ZSW(_uri->user.s));
136 130
 			uridb_dbf.free_result(db_handle, res);
137 131
 			return 1;
138 132
 		}
... ...
@@ -140,9 +134,9 @@ static inline int check_username(struct sip_msg* _m, str* _uri)
140 134
 		/* URI table not used, simply compare digest username and From/To
141 135
 		 * username, the comparison is case insensitive
142 136
 		 */
143
-		if (puri.user.len == c->digest.username.user.len) {
144
-			if (!strncasecmp(puri.user.s, c->digest.username.user.s, 
145
-			puri.user.len)) {
137
+		if (_uri->user.len == c->digest.username.user.len) {
138
+			if (!strncasecmp(_uri->user.s, c->digest.username.user.s, 
139
+			_uri->user.len)) {
146 140
 				DBG("check_username(): Digest username and URI "
147 141
 					"username match\n");
148 142
 				return 1;
... ...
@@ -165,7 +159,12 @@ int check_to(struct sip_msg* _m, char* _s1, char* _s2)
165 159
 		LOG(L_ERR, "check_to(): Error while parsing To header field\n");
166 160
 		return -1;
167 161
 	}
168
-	return check_username(_m, &get_to(_m)->uri);
162
+	if(parse_to_uri(_m)==NULL) {
163
+		LOG(L_ERR, "check_to(): Error while parsing To header URI\n");
164
+		return -1;
165
+	}
166
+
167
+	return check_username(_m, &get_to(_m)->parsed_uri);
169 168
 }
170 169
 
171 170
 
... ...
@@ -178,8 +177,12 @@ int check_from(struct sip_msg* _m, char* _s1, char* _s2)
178 177
 		LOG(L_ERR, "check_from(): Error while parsing From header field\n");
179 178
 		return -1;
180 179
 	}
180
+	if(parse_from_uri(_m)==NULL) {
181
+		LOG(L_ERR, "check_from(): Error while parsing From header URI\n");
182
+		return -1;
183
+	}
181 184
 
182
-	return check_username(_m, &get_from(_m)->uri);
185
+	return check_username(_m, &get_from(_m)->parsed_uri);
183 186
 }
184 187
 
185 188
 
... ...
@@ -60,11 +60,11 @@ void destroy(void);
60 60
 
61 61
 static cmd_export_t cmds[]={
62 62
 	{"xlog",  xlog_1,  1, xdbg_fixup, REQUEST_ROUTE | FAILURE_ROUTE |
63
-		ONREPLY_ROUTE | BRANCH_ROUTE},
63
+		ONREPLY_ROUTE | BRANCH_ROUTE | ERROR_ROUTE},
64 64
 	{"xlog",  xlog_2,  2, xlog_fixup, REQUEST_ROUTE | FAILURE_ROUTE |
65
-		ONREPLY_ROUTE | BRANCH_ROUTE},
65
+		ONREPLY_ROUTE | BRANCH_ROUTE | ERROR_ROUTE},
66 66
 	{"xdbg",  xdbg,    1, xdbg_fixup, REQUEST_ROUTE | FAILURE_ROUTE | 
67
-		ONREPLY_ROUTE | BRANCH_ROUTE },
67
+		ONREPLY_ROUTE | BRANCH_ROUTE | ERROR_ROUTE},
68 68
 	{0,0,0,0,0}
69 69
 };
70 70