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