00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <string.h>
00024
00025 #include "../../mem/shm_mem.h"
00026 #include "../../sr_module.h"
00027 #include "../../lib/kmi/mi.h"
00028 #include "../../mem/mem.h"
00029 #include "../../usr_avp.h"
00030 #include "../../locking.h"
00031 #include "../../error.h"
00032 #include "../../ut.h"
00033 #include "../../mod_fix.h"
00034
00035 #include "db_matrix.h"
00036
00037 MODULE_VERSION
00038
00039
00040
00041
00042 #define MAXCOLS 1000
00043
00044
00045
00046
00047 str matrix_db_url = str_init(DEFAULT_RODB_URL);
00048
00049
00050
00051
00056 struct multiparam_t {
00057 enum {
00058 MP_INT,
00059 MP_STR,
00060 MP_AVP,
00061 MP_PVE,
00062 } type;
00063 union {
00064 int n;
00065 str s;
00066 struct {
00067 unsigned short flags;
00068 int_str name;
00069 } a;
00070 pv_elem_t *p;
00071 } u;
00072 };
00073
00074
00075
00076
00077
00078 static int matrix_fixup(void** param, int param_no);
00079
00080
00081 static int lookup_matrix(struct sip_msg *msg, struct multiparam_t *_first, struct multiparam_t *_second, struct multiparam_t *_dstavp);
00082
00083
00084 static int mod_init(void);
00085 static int child_init(int rank);
00086 static int mi_child_init(void);
00087 static void mod_destroy(void);
00088
00089
00090 struct mi_root * mi_reload_matrix(struct mi_root* cmd, void* param);
00091
00092
00093
00094
00095 static cmd_export_t cmds[]={
00096 { "matrix", (cmd_function)lookup_matrix, 3, matrix_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00097 { 0, 0, 0, 0, 0, 0}
00098 };
00099
00100
00101
00102
00103 static param_export_t params[] = {
00104 matrix_DB_URL
00105 matrix_DB_TABLE
00106 matrix_DB_COLS
00107 { 0, 0, 0}
00108 };
00109
00110
00111
00112
00113
00114 static mi_export_t mi_cmds[] = {
00115 { "reload_matrix", mi_reload_matrix, MI_NO_INPUT_FLAG, 0, mi_child_init },
00116 { 0, 0, 0, 0, 0}
00117 };
00118
00119
00120
00121
00122 struct module_exports exports= {
00123 "matrix",
00124 DEFAULT_DLFLAGS,
00125 cmds,
00126 params,
00127 0,
00128 mi_cmds,
00129 0,
00130 0,
00131 mod_init,
00132 0,
00133 mod_destroy,
00134 child_init
00135 };
00136
00137
00138
00139
00140 struct first_t {
00141 struct first_t *next;
00142 int id;
00143 short int second_list[MAXCOLS+1];
00144 };
00145
00146
00147
00148
00149 struct matrix_t {
00150 struct first_t *head;
00151 };
00152
00153
00154
00155
00156 static gen_lock_t *lock = NULL;
00157 static struct matrix_t *matrix = NULL;
00158
00159
00160
00161
00170 static int mp_fixup(void ** param) {
00171 pv_spec_t avp_spec;
00172 struct multiparam_t *mp;
00173 str s;
00174
00175 mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
00176 if (mp == NULL) {
00177 LM_ERR("out of pkg memory\n");
00178 return -1;
00179 }
00180 memset(mp, 0, sizeof(struct multiparam_t));
00181
00182 s.s = (char *)(*param);
00183 s.len = strlen(s.s);
00184
00185 if (s.s[0]!='$') {
00186
00187 mp->type=MP_STR;
00188 mp->u.s=s;
00189 }
00190 else {
00191
00192 if (pv_parse_spec(&s, &avp_spec)==0) {
00193 LM_ERR("pv_parse_spec failed for '%s'\n", (char *)(*param));
00194 pkg_free(mp);
00195 return -1;
00196 }
00197 if (avp_spec.type==PVT_AVP) {
00198
00199 mp->type=MP_AVP;
00200 if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
00201 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
00202 pkg_free(mp);
00203 return -1;
00204 }
00205 } else {
00206 mp->type=MP_PVE;
00207 if(pv_parse_format(&s, &(mp->u.p))<0) {
00208 LM_ERR("pv_parse_format failed for '%s'\n", (char *)(*param));
00209 pkg_free(mp);
00210 return -1;
00211 }
00212 }
00213 }
00214 *param = (void*)mp;
00215
00216 return 0;
00217 }
00218
00219
00220
00221
00229 static int avp_name_fixup(void ** param) {
00230 pv_spec_t avp_spec;
00231 struct multiparam_t *mp;
00232 str s;
00233
00234 s.s = (char *)(*param);
00235 s.len = strlen(s.s);
00236 if (s.len <= 0) return -1;
00237 if (pv_parse_spec(&s, &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
00238 LM_ERR("Malformed or non AVP definition <%s>\n", (char *)(*param));
00239 return -1;
00240 }
00241
00242 mp = (struct multiparam_t *)pkg_malloc(sizeof(struct multiparam_t));
00243 if (mp == NULL) {
00244 LM_ERR("out of pkg memory\n");
00245 return -1;
00246 }
00247 memset(mp, 0, sizeof(struct multiparam_t));
00248
00249 mp->type=MP_AVP;
00250 if(pv_get_avp_name(0, &(avp_spec.pvp), &(mp->u.a.name), &(mp->u.a.flags))!=0) {
00251 LM_ERR("Invalid AVP definition <%s>\n", (char *)(*param));
00252 pkg_free(mp);
00253 return -1;
00254 }
00255
00256 *param = (void*)mp;
00257
00258 return 0;
00259 }
00260
00261
00262
00263
00264 static int matrix_fixup(void** param, int param_no)
00265 {
00266 if (param_no == 1) {
00267
00268 if (mp_fixup(param) < 0) {
00269 LM_ERR("cannot fixup parameter %d\n", param_no);
00270 return -1;
00271 }
00272 }
00273 else if (param_no == 2) {
00274
00275 if (mp_fixup(param) < 0) {
00276 LM_ERR("cannot fixup parameter %d\n", param_no);
00277 return -1;
00278 }
00279 }
00280 else if (param_no == 3) {
00281
00282 if (avp_name_fixup(param) < 0) {
00283 LM_ERR("cannot fixup parameter %d\n", param_no);
00284 return -1;
00285 }
00286 }
00287
00288 return 0;
00289 }
00290
00291
00292
00293
00294 static void matrix_clear(void)
00295 {
00296 struct first_t *srcitem;
00297 if (matrix) {
00298 while (matrix->head) {
00299 srcitem = matrix->head;
00300 matrix->head = srcitem->next;
00301 shm_free(srcitem);
00302 }
00303 }
00304 }
00305
00306
00307
00308
00309 static int matrix_insert(int first, short int second, int res)
00310 {
00311 struct first_t *srcitem;
00312 int i;
00313
00314 if ((second<0) || (second>MAXCOLS)) {
00315 LM_ERR("invalid second value %d\n", second);
00316 return -1;
00317 }
00318 LM_DBG("searching for %d, %d\n", first, second);
00319 if (matrix) {
00320 srcitem = matrix->head;
00321 while (srcitem) {
00322 if (srcitem->id == first) {
00323 srcitem->second_list[second] = res;
00324 LM_DBG("inserted (%d, %d, %d)", first, second, res);
00325 return 0;
00326 }
00327 srcitem = srcitem->next;
00328 }
00329
00330 srcitem = shm_malloc(sizeof(struct first_t));
00331 if (srcitem == NULL) {
00332 LM_ERR("out of shared memory.");
00333 return -1;
00334 }
00335 memset(srcitem, 0, sizeof(struct first_t));
00336
00337
00338 for (i=0; i<=MAXCOLS; i++) srcitem->second_list[i] = -1;
00339
00340 srcitem->next = matrix->head;
00341 srcitem->id = first;
00342 srcitem->second_list[second] = res;
00343 matrix->head = srcitem;
00344 }
00345
00346 LM_DBG("inserted new row for (%d, %d, %d)", first, second, res);
00347 return 0;
00348 }
00349
00350
00351
00352
00353
00354
00355 static int internal_lookup(int first, short int second)
00356 {
00357 struct first_t *item;
00358
00359 if ((second<0) || (second>MAXCOLS)) {
00360 LM_ERR("invalid second value %d\n", second);
00361 return -1;
00362 }
00363
00364 if (matrix) {
00365 item = matrix->head;
00366 while (item) {
00367 if (item->id == first) {
00368 return item->second_list[second];
00369 }
00370 item = item->next;
00371 }
00372 }
00373
00374 return -1;
00375 }
00376
00377
00378
00379
00380 static int lookup_matrix(struct sip_msg *msg, struct multiparam_t *_srctree, struct multiparam_t *_second, struct multiparam_t *_dstavp)
00381 {
00382 int first;
00383 int second;
00384 struct usr_avp *avp;
00385 int_str avp_val;
00386
00387 switch (_srctree->type) {
00388 case MP_INT:
00389 first = _srctree->u.n;
00390 break;
00391 case MP_AVP:
00392 avp = search_first_avp(_srctree->u.a.flags, _srctree->u.a.name, &avp_val, 0);
00393 if (!avp) {
00394 LM_ERR("cannot find srctree AVP\n");
00395 return -1;
00396 }
00397 if ((avp->flags&AVP_VAL_STR)) {
00398 LM_ERR("cannot process string value in srctree AVP\n");
00399 return -1;
00400 }
00401 else first = avp_val.n;
00402 break;
00403 default:
00404 LM_ERR("invalid srctree type\n");
00405 return -1;
00406 }
00407
00408 switch (_second->type) {
00409 case MP_INT:
00410 second = _second->u.n;
00411 break;
00412 case MP_AVP:
00413 avp = search_first_avp(_second->u.a.flags, _second->u.a.name, &avp_val, 0);
00414 if (!avp) {
00415 LM_ERR("cannot find second_value AVP\n");
00416 return -1;
00417 }
00418 if ((avp->flags&AVP_VAL_STR)) {
00419 LM_ERR("cannot process string value in second_value AVP\n");
00420 return -1;
00421 }
00422 else second = avp_val.n;
00423 break;
00424 default:
00425 LM_ERR("invalid second_value type\n");
00426 return -1;
00427 }
00428
00429
00430
00431 lock_get(lock);
00432
00433 avp_val.n=internal_lookup(first, second);
00434
00435
00436 lock_release(lock);
00437
00438 if (avp_val.n<0) {
00439 LM_INFO("lookup failed\n");
00440 return -1;
00441 }
00442
00443
00444 if (add_avp(_dstavp->u.a.flags, _dstavp->u.a.name, avp_val)<0) {
00445 LM_ERR("add AVP failed\n");
00446 return -1;
00447 }
00448 LM_INFO("result from lookup: %d\n", avp_val.n);
00449 return 1;
00450 }
00451
00452
00453
00454
00459 static int db_reload_matrix(void)
00460 {
00461 db_key_t columns[3] = { &matrix_first_col, &matrix_second_col, &matrix_res_col };
00462 db1_res_t *res;
00463 int i;
00464 int n = 0;
00465
00466 if (matrix_dbf.use_table(matrix_dbh, &matrix_table) < 0) {
00467 LM_ERR("cannot use table '%.*s'.\n", matrix_table.len, matrix_table.s);
00468 return -1;
00469 }
00470 if (matrix_dbf.query(matrix_dbh, NULL, NULL, NULL, columns, 0, 3, NULL, &res) < 0) {
00471 LM_ERR("error while executing query.\n");
00472 return -1;
00473 }
00474
00475
00476 lock_get(lock);
00477
00478 matrix_clear();
00479
00480 if (RES_COL_N(res) > 2) {
00481 for(i = 0; i < RES_ROW_N(res); i++) {
00482 if ((!RES_ROWS(res)[i].values[0].nul) && (!RES_ROWS(res)[i].values[1].nul)) {
00483 if ((RES_ROWS(res)[i].values[0].type == DB1_INT) &&
00484 (RES_ROWS(res)[i].values[1].type == DB1_INT) &&
00485 (RES_ROWS(res)[i].values[2].type == DB1_INT)) {
00486 matrix_insert(RES_ROWS(res)[i].values[0].val.int_val, RES_ROWS(res)[i].values[1].val.int_val, RES_ROWS(res)[i].values[2].val.int_val);
00487 n++;
00488 }
00489 else {
00490 LM_ERR("got invalid result type from query.\n");
00491 }
00492 }
00493 }
00494 }
00495
00496
00497 lock_release(lock);
00498
00499 matrix_dbf.free_result(matrix_dbh, res);
00500
00501 LM_INFO("loaded %d matrix entries.", n);
00502 return n;
00503 }
00504
00505
00506
00507
00508 static int init_shmlock(void)
00509 {
00510 lock = lock_alloc();
00511 if (!lock) {
00512 LM_CRIT("cannot allocate memory for lock.\n");
00513 return -1;
00514 }
00515 if (lock_init(lock) == 0) {
00516 LM_CRIT("cannot initialize lock.\n");
00517 return -1;
00518 }
00519
00520 return 0;
00521 }
00522
00523
00524
00525
00526 static void destroy_shmlock(void)
00527 {
00528 if (lock) {
00529 lock_destroy(lock);
00530 lock_dealloc((void *)lock);
00531 lock = NULL;
00532 }
00533 }
00534
00535
00536
00537
00538 struct mi_root * mi_reload_matrix(struct mi_root* cmd, void* param)
00539 {
00540 struct mi_root * tmp = NULL;
00541 if(db_reload_matrix() >= 0) {
00542 tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00543 } else {
00544 tmp = init_mi_tree( 500, "cannot reload matrix", 24);
00545 }
00546
00547 return tmp;
00548 }
00549
00550
00551
00552
00553 static int init_matrix(void)
00554 {
00555 matrix = shm_malloc(sizeof(struct matrix_t));
00556 if (!matrix) {
00557 LM_ERR("out of shared memory\n");
00558 return -1;
00559 }
00560 memset(matrix, 0, sizeof(struct matrix_t));
00561 if (db_reload_matrix() < 0) {
00562 LM_ERR("cannot populate matrix\n");
00563 return -1;
00564 }
00565
00566 return 0;
00567 }
00568
00569
00570
00571
00572 static void destroy_matrix(void)
00573 {
00574 if (matrix) {
00575 matrix_clear();
00576 shm_free(matrix);
00577 }
00578 }
00579
00580
00581
00582
00583 static int mod_init(void)
00584 {
00585 matrix_db_vars();
00586
00587 if (init_shmlock() != 0) return -1;
00588 if (matrix_db_init() != 0) return -1;
00589 if (matrix_db_open() != 0) return -1;
00590 if (init_matrix() != 0) return -1;
00591 matrix_db_close();
00592 return 0;
00593 }
00594
00595
00596
00597
00598 static int child_init(int rank)
00599 {
00600 if(rank==PROC_INIT || rank==PROC_TCP_MAIN)
00601 return 0;
00602 if (matrix_db_open() != 0) return -1;
00603 return 0;
00604 }
00605
00606
00607
00608
00609 static int mi_child_init(void)
00610 {
00611 if (matrix_db_open() != 0) return -1;
00612 return 0;
00613 }
00614
00615
00616
00617
00618 static void mod_destroy(void)
00619 {
00620 destroy_matrix();
00621 destroy_shmlock();
00622 matrix_db_close();
00623 }