Browse code

- final version of user preferences (AVP) support

Bogdan-Andrei Iancu authored on 10/02/2004 17:38:04
Showing 2 changed files
... ...
@@ -32,8 +32,12 @@
32 32
 
33 33
 #include "sr_module.h"
34 34
 #include "dprint.h"
35
+#include "str.h"
36
+#include "ut.h"
35 37
 #include "mem/mem.h"
36 38
 #include "db/db.h"
39
+#include "parser/parse_from.h"
40
+#include "parser/parse_uri.h"
37 41
 #include "usr_avp.h"
38 42
 
39 43
 
... ...
@@ -49,7 +53,7 @@ static char* usr_type[] = {"ruri","from","to",0};
49 53
 int init_avp_child( int rank )
50 54
 {
51 55
 	if ( rank>PROC_MAIN ) {
52
-		if (avp_db_con==0) {
56
+		if (avp_db_url==0) {
53 57
 			LOG(L_NOTICE,"NOTICE:init_avp_child: no avp_db_url specified "
54 58
 				"-> feature disabled\n");
55 59
 			return 0;
... ...
@@ -64,17 +68,38 @@ int init_avp_child( int rank )
64 68
 			LOG(L_ERR,"ERROR:init_avp_child: unable to connect to database\n");
65 69
 			return -1;
66 70
 		}
71
+		if (db_use_table( avp_db_con, AVP_DB_TABLE )<0) {
72
+			/* table selection failed */
73
+			LOG(L_ERR,"ERROR:init_avp_child: unable to select db table\n");
74
+			return -1;
75
+		}
67 76
 	}
68 77
 
69 78
 	return 0;
70 79
 }
71 80
 
72 81
 
82
+void print_avps(struct usr_avp *avp)
83
+{
84
+	if (!avp)
85
+		return;
86
+	if (avp->val_type==AVP_TYPE_STR)
87
+		DBG("DEBUG:print_avp: %.*s=%.*s\n",
88
+			avp->attr.len,avp->attr.s,
89
+			avp->val.str_val.len,avp->val.str_val.s);
90
+	else
91
+		DBG("DEBUG:print_avp: %.*s=%u\n",
92
+			avp->attr.len,avp->attr.s,
93
+			avp->val.uint_val);
94
+	print_avps(avp->next);
95
+}
96
+
73 97
 
74 98
 void destroy_avps( )
75 99
 {
76 100
 	struct usr_avp *avp;
77 101
 
102
+	/*print_avps(users_avps);*/
78 103
 	while (users_avps) {
79 104
 		avp = users_avps;
80 105
 		users_avps = users_avps->next;
... ...
@@ -98,9 +123,242 @@ int get_user_type( char *id )
98 123
 }
99 124
 
100 125
 
101
-int load_avp( struct sip_msg *msg, int type, char *attr, int use_dom)
126
+
127
+inline static unsigned int compute_ID( str *attr )
128
+{
129
+	char *p;
130
+	unsigned int id;
131
+
132
+	id=0;
133
+	for( p=attr->s+attr->len-1 ; p>=attr->s ; p-- )
134
+		id ^= *p;
135
+	return id;
136
+}
137
+
138
+
139
+inline static db_res_t *do_db_query(struct sip_uri *uri,char *attr,int use_dom)
140
+{
141
+	static db_key_t   keys_cmp[3] = {"username","domain","attribute"};
142
+	static db_key_t   keys_ret[] = {"attribute","value","type"};
143
+	static db_val_t   vals_cmp[3];
144
+	unsigned int      nr_keys_cmp;
145
+	db_res_t          *res;
146
+
147
+	/* prepare DB query */
148
+	nr_keys_cmp = 0;
149
+	keys_cmp[ nr_keys_cmp ] = "username";
150
+	vals_cmp[ nr_keys_cmp ].type = DB_STR;
151
+	vals_cmp[ nr_keys_cmp ].nul  = 0;
152
+	vals_cmp[ nr_keys_cmp ].val.str_val = uri->user;
153
+	nr_keys_cmp++;
154
+	if (use_dom) {
155
+		keys_cmp[ nr_keys_cmp ] = "domain";
156
+		vals_cmp[ nr_keys_cmp ].type = DB_STR;
157
+		vals_cmp[ nr_keys_cmp ].nul  = 0;
158
+		vals_cmp[ nr_keys_cmp ].val.str_val = uri->host;
159
+		nr_keys_cmp++;
160
+	}
161
+	if (attr) {
162
+		keys_cmp[ nr_keys_cmp ] = "attribute";
163
+		vals_cmp[ nr_keys_cmp ].type = DB_STRING;
164
+		vals_cmp[ nr_keys_cmp ].nul  = 0;
165
+		vals_cmp[ nr_keys_cmp ].val.string_val = attr;
166
+		nr_keys_cmp++;
167
+	}
168
+
169
+	/* do the DB query */
170
+	if ( db_query( avp_db_con, keys_cmp, 0/*op*/, vals_cmp, keys_ret,
171
+	nr_keys_cmp, 3, 0/*order*/, &res) < 0)
172
+		return 0;
173
+
174
+	return res;
175
+}
176
+
177
+
178
+
179
+inline static int validate_db_row(struct db_row *row, unsigned int *val_type,
180
+													unsigned int *uint_val)
181
+{
182
+	/* we don't accept null values */
183
+	if (row->values[0].nul || row->values[1].nul || row->values[2].nul ) {
184
+		LOG(L_ERR,"ERROR:avp:validat_db_row: DBreply contains NULL entryes\n");
185
+		return -1;
186
+	}
187
+	/* check the value types */
188
+	if (row->values[0].type!=DB_STRING || row->values[1].type!=DB_STRING ||
189
+	row->values[2].type!=DB_INT ) {
190
+		LOG(L_ERR,"ERROR:avp:validat_db_row: bad DB types in response\n");
191
+		return -1;
192
+	}
193
+	/* check the content of TYPE filed */
194
+	*val_type = (unsigned int)row->values[2].val.int_val;
195
+	if (*val_type!=AVP_TYPE_INT && *val_type!=AVP_TYPE_STR) {
196
+		LOG(L_ERR,"ERROR:avp:validat_db_row: bad val %d in type field\n",
197
+			*val_type);
198
+		return -1;
199
+	}
200
+	/* convert from DB_STRING to DB_STR */
201
+	row->values[0].val.str_val.s =  (char*)row->values[0].val.string_val;
202
+	row->values[0].val.str_val.len = strlen(row->values[0].val.str_val.s);
203
+	row->values[1].val.str_val.s =  (char*)row->values[1].val.string_val;
204
+	row->values[1].val.str_val.len = strlen(row->values[1].val.str_val.s);
205
+	/* if type is INT decode the value */
206
+	if ( *val_type==AVP_TYPE_INT &&
207
+	str2int( &row->values[1].val.str_val, uint_val)==-1 ) {
208
+		LOG(L_ERR,"ERROR:avp:validat_db_row: type is INT, but value not "
209
+			"<%s>\n",row->values[1].val.str_val.s);
210
+		return -1;
211
+	}
212
+	return 0;
213
+}
214
+
215
+
216
+
217
+#define copy_str(_p_,_sd_,_ss_) \
218
+	do {\
219
+		(_sd_).s = (_p_);\
220
+		(_sd_).len = (_ss_).len;\
221
+		memcpy( _p_, (_ss_).s, (_ss_).len);\
222
+		(_p_) += (_ss_).len;\
223
+	}while(0)
224
+
225
+int load_avp( struct sip_msg *msg, int uri_type, char *attr, int use_dom)
226
+{
227
+	db_res_t          *res;
228
+	struct sip_uri    uri;
229
+	struct usr_avp    *avp;
230
+	str               *uri_s;
231
+	int               n;
232
+	unsigned int      val_type;
233
+	unsigned int      uint_val;
234
+	int               len;
235
+	char              *p;
236
+
237
+	/*
238
+	DBG("----load_avp:%d,%s,%d\n",uri_type,attr?attr:"NULL",use_dom);
239
+	*/
240
+
241
+	/* featch the user name [and domain] */
242
+	switch (uri_type) {
243
+		case 0: /* RURI */
244
+			uri_s = &(msg->first_line.u.request.uri);
245
+			break;
246
+		case 1: /* from */
247
+			if (parse_from_header( msg )<0 ) {
248
+				LOG(L_ERR,"ERROR:load_avp: failed to parse from\n");
249
+				goto error;
250
+			}
251
+			uri_s = &(get_from(msg)->uri);
252
+			break;
253
+		case 2: /* to */
254
+			if (parse_headers( msg, HDR_TO, 0)<0) {
255
+				LOG(L_ERR,"ERROR:load_avp: failed to parse to\n");
256
+				goto error;
257
+			}
258
+			uri_s = &(get_to(msg)->uri);
259
+			break;
260
+		default:
261
+			LOG(L_CRIT,"BUG:load_avp: unknow username type <%d>\n",uri_type);
262
+			goto error;
263
+	}
264
+
265
+	/* parse uri */
266
+	if (parse_uri( uri_s->s, uri_s->len , &uri )<0) {
267
+		LOG(L_ERR,"ERROR:load_avp: failed to parse uri\n");
268
+		goto error;
269
+	}
270
+
271
+	/* check uri */
272
+	if (!uri.user.s||!uri.user.len||(use_dom&&(!uri.host.len||!uri.host.s))) {
273
+		LOG(L_ERR,"ERROR:load_avp: uri has no user/host part <%.*s>\n",
274
+			uri_s->len,uri_s->s);
275
+		goto error;
276
+	}
277
+
278
+	/* do DB query */
279
+	if ( (res=do_db_query( &uri, attr,use_dom))==0 ) {
280
+		LOG(L_ERR,"ERROR:load_avp: db_query failed\n");
281
+		goto error;
282
+	}
283
+
284
+	/* process DB response */
285
+	if (res->n==0) {
286
+		DBG("DEBUG:load_avp: no avp found for %.*s@%.*s <%s>\n",
287
+			uri.user.len,uri.user.s,(use_dom!=0)*uri.host.len,uri.host.s,
288
+			attr?attr:"NULL");
289
+	} else {
290
+		for( n=0 ; n<res->n ; n++) {
291
+			/* validate row */
292
+			if (validate_db_row( &res->rows[n] ,&val_type, &uint_val) < 0 )
293
+				continue;
294
+			/* what do we have here?! */
295
+			DBG("DEBUG:load_avp: found avp: <%s,%s,%d>\n",
296
+				res->rows[n].values[0].val.string_val,
297
+				res->rows[n].values[1].val.string_val,
298
+				res->rows[n].values[2].val.int_val);
299
+			/* build a new avp struct */
300
+			len = sizeof(struct usr_avp);
301
+			len += res->rows[n].values[0].val.str_val.len ;
302
+			if (val_type==AVP_TYPE_STR)
303
+				len += res->rows[n].values[1].val.str_val.len ;
304
+			avp = (struct usr_avp*)pkg_malloc( len );
305
+			if (avp==0) {
306
+				LOG(L_ERR,"ERROR:load_avp: no more pkg mem\n");
307
+				continue;
308
+			}
309
+			/* fill the structure in */
310
+			p = ((char*)avp) + sizeof(struct usr_avp);
311
+			avp->id = compute_ID( &res->rows[n].values[0].val.str_val );
312
+			avp->val_type = val_type;
313
+			/* attribute name */
314
+			copy_str( p, avp->attr, res->rows[n].values[0].val.str_val);
315
+			if (val_type==AVP_TYPE_INT) {
316
+				/* INT */
317
+				avp->val.uint_val = uint_val;
318
+			} else {
319
+				/* STRING */
320
+				copy_str( p, avp->val.str_val,
321
+					res->rows[n].values[1].val.str_val);
322
+			}
323
+			/* add avp to internal list */
324
+			avp->next = users_avps;
325
+			users_avps = avp;
326
+		}
327
+	}
328
+
329
+	db_free_query( avp_db_con, res);
330
+	return 0;
331
+error:
332
+	return -1;
333
+}
334
+
335
+
336
+
337
+inline static struct usr_avp *internal_search_avp( unsigned int id, str *attr)
338
+{
339
+	struct usr_avp *avp;
340
+
341
+	for( avp=users_avps ; avp ; avp=avp->next )
342
+		if ( id==avp->id 
343
+		&& attr->len==avp->attr.len
344
+		&& !strncasecmp( attr->s, avp->attr.s, attr->len)
345
+		) {
346
+			return avp;
347
+		}
348
+	return 0;
349
+}
350
+
351
+
352
+
353
+struct usr_avp *search_avp( str *attr)
354
+{
355
+	return internal_search_avp( compute_ID( attr ), attr);
356
+}
357
+
358
+
359
+
360
+struct usr_avp *search_next_avp( struct usr_avp *avp )
102 361
 {
103
-	DBG("----load_avp:%d,%s,%d\n",type,attr?attr:"NULL",use_dom);
104
-	return 1;
362
+	return internal_search_avp( avp->id, &avp->attr);
105 363
 }
106 364
 
... ...
@@ -39,9 +39,10 @@
39 39
 struct usr_avp {
40 40
 	unsigned int id;
41 41
 	str attr;
42
+	unsigned int val_type;
42 43
 	union {
43 44
 		str  str_val;
44
-		unsigned int int_val;
45
+		unsigned int uint_val;
45 46
 	}val;
46 47
 	struct usr_avp *next;
47 48
 };
... ...
@@ -49,13 +50,17 @@ struct usr_avp {
49 50
 extern struct usr_avp   *users_avps;
50 51
 
51 52
 
53
+#define AVP_TYPE_INT     1
54
+#define AVP_TYPE_STR     2
55
+
56
+#define AVP_DB_TABLE     "usr_preferences"
57
+
52 58
 #define AVP_USER_RURI    1
53 59
 #define AVP_USER_FROM    2
54 60
 #define AVP_USER_TO      3
55 61
 
56 62
 #define AVP_ALL_ATTR     ((char*)0xffffffff)
57 63
 
58
-
59 64
 /* init function */
60 65
 int init_avp_child( int rank );
61 66
 int get_user_type( char *id );
... ...
@@ -63,6 +68,8 @@ int get_user_type( char *id );
63 68
 /* load/free/seach functions */
64 69
 void destroy_avps( );
65 70
 int load_avp( struct sip_msg *msg, int type, char *attr, int use_dom);
71
+struct usr_avp *search_avp( str *attr);
72
+struct usr_avp *search_next_avp( struct usr_avp *avp );
66 73
 
67 74
 #endif
68 75