db_rls.c

00001 #include <time.h>
00002 #include <cds/logger.h>
00003 
00004 #include "rl_subscription.h"
00005 #include "rls_mod.h"
00006 
00007 char *rls_table = "rls_subscription";
00008 char *vs_table = "rls_vs";
00009 char *vs_names_table = "rls_vs_names";
00010 
00011 /* generate ID for given data */
00012 void generate_db_id(db_id_t *id, void *data)
00013 {
00014         if (id) {
00015                 snprintf(*id, sizeof(*id), "%px%xx%x", 
00016                                 data, (int)time(NULL), rand());
00017                 /* DEBUG_LOG("generated DB ID = %s\n", *id); */
00018         }
00019 }
00020 
00021 #define string_val(v,s) (v).type = DB_STR; \
00022         (v).val.str_val=s; \
00023         (v).nul=(s.len == 0); 
00024 
00025 #define int_val(v,i)    (v).type = DB_INT; \
00026         (v).val.int_val=i;\
00027         (v).nul=0; 
00028 
00029 #define time_val(v,t)   (v).type = DB_DATETIME; \
00030         (v).val.time_val=t;\
00031         (v).nul=0; 
00032 
00033 #define string_val_ex(v,str,l)  (v).type = DB_STR; \
00034         (v).val.str_val.s=str; \
00035         (v).val.str_val.len=l; \
00036         (v).nul=0; 
00037 
00038 #define blob_val(v,str) (v).type = DB_BLOB; \
00039         (v).val.blob_val=str; \
00040         (v).nul=0; 
00041 
00042 
00043 /* ------------- virtual subscriptions ------------- */
00044 
00045 static int virtual_subscription_db_add(virtual_subscription_t *vs, rl_subscription_t *s)
00046 {
00047         db_key_t cols[20];
00048         db_val_t vals[20];
00049         int n = -1;
00050         int i, cnt;
00051         vs_display_name_t *dn;
00052 
00053         DEBUG_LOG("storing into database\n");
00054         
00055         if (rls_dbf.use_table(rls_db, vs_table) < 0) {
00056                 LOG(L_ERR, "vsub_db_add: Error in use_table\n");
00057                 return -1;
00058         }
00059         
00060         cols[++n] = "uri";
00061         string_val(vals[n], vs->uri);
00062         
00063         cols[++n] = "id";
00064         string_val_ex(vals[n], vs->dbid, strlen(vs->dbid));
00065         
00066         cols[++n] = "rls_id";
00067         string_val_ex(vals[n], s->dbid, strlen(s->dbid));
00068         
00069         /* insert new record into database */
00070         if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
00071                 LOG(L_ERR, "vsub_db_add: Error while inserting virtual subscription\n");
00072                 return -1;
00073         }
00074 
00075         /* store display names */
00076         cnt = vector_size(&vs->display_names);
00077         for (i = 0; i < cnt; i++) {
00078                 if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
00079                         LOG(L_ERR, "vsub_db_add (names): Error in use_table\n");
00080                         return -1;
00081                 }
00082                 dn = vector_get_ptr(&vs->display_names, i);
00083                 if (!dn) continue;
00084 
00085                 n = -1;
00086                 
00087                 cols[++n] = "id";
00088                 string_val_ex(vals[n], vs->dbid, strlen(vs->dbid));
00089                 
00090                 cols[++n] = "name";
00091                 string_val(vals[n], dn->name);
00092                 
00093                 cols[++n] = "lang";
00094                 string_val(vals[n], dn->lang);
00095         
00096                 if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
00097                         LOG(L_ERR, "vsub_db_add: Error while inserting name\n");
00098                         return -1;
00099                 }
00100         }
00101         
00102         return 0;
00103 }
00104 
00105 static int vs_db_add(rl_subscription_t *s)
00106 {
00107         int i, cnt;
00108         int res = 0;
00109         virtual_subscription_t *vs;
00110         
00111         cnt = ptr_vector_size(&s->vs);
00112         for (i = 0; i < cnt; i++) {
00113                 vs = ptr_vector_get(&s->vs, i);
00114                 if (!vs) continue;
00115 
00116                 res = virtual_subscription_db_add(vs, s);
00117                 if (res != 0) break;
00118         }
00119         return res;
00120 }
00121 
00122 static int vs_db_update(rl_subscription_t *s)
00123 {
00124         /* There is nothing to be updated now - may be dialogs for
00125          * external subscriptions and their expirations 
00126          * in the future ! 
00127          *
00128          * Status is newly generated on the other side (in PA)! */
00129         return 0;
00130 }
00131 
00132 static int vs_db_remove(rl_subscription_t *s)
00133 {
00134         db_key_t keys[] = { "id" };
00135         db_op_t ops[] = { OP_EQ };
00136         db_val_t k_vals[1];
00137         int i, cnt;
00138         int res = 0;
00139         virtual_subscription_t *vs;
00140         
00141         cnt = ptr_vector_size(&s->vs);
00142         for (i = 0; i < cnt; i++) {
00143                 vs = ptr_vector_get(&s->vs, i);
00144                 if (!vs) continue;
00145                 
00146                 string_val_ex(k_vals[0], vs->dbid, strlen(vs->dbid));
00147                 
00148                 /* remove virtual subscription */
00149                 if (rls_dbf.use_table(rls_db, vs_table) < 0) {
00150                         LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
00151                         res = -1;
00152                 }
00153                 if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
00154                         LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
00155                         res = -1;
00156                 }
00157                 
00158                 /* remove display names */
00159                 if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
00160                         LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
00161                         res = -1;
00162                 }
00163                 if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
00164                         LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
00165                         res = -1;
00166                 }
00167         }
00168         
00169         return res;
00170 }
00171 
00172 /* ------------- rls subscriptions ------------- */
00173 
00174 int rls_db_add(rl_subscription_t *s)
00175 {
00176         db_key_t cols[20];
00177         db_val_t vals[20];
00178         str_t dialog = STR_NULL;
00179         str_t str_xcap_params = STR_NULL;
00180         int n = -1;
00181         int res = 0;
00182         time_t t;
00183 
00184         if (!use_db) return 0;
00185 
00186         /* store only external subscriptions */
00187         if (s->type != rls_external_subscription) return 0;
00188         
00189         DEBUG_LOG("storing into database\n");
00190         
00191         if (rls_dbf.use_table(rls_db, rls_table) < 0) {
00192                 LOG(L_ERR, "rls_db_add: Error in use_table\n");
00193                 return -1;
00194         }
00195         
00196         cols[++n] = "doc_version";
00197         int_val(vals[n], s->doc_version);
00198         
00199         cols[++n] = "status";
00200         int_val(vals[n], s->u.external.status);
00201         
00202         t = time(NULL);
00203         t += rls_subscription_expires_in(s);
00204         cols[++n] = "expires";
00205         time_val(vals[n], t);
00206         
00207         if (dlg_func.dlg2str(s->u.external.dialog, &dialog) != 0) {     
00208                 LOG(L_ERR, "Error while serializing dialog\n");
00209                 return -1;
00210         }
00211         cols[++n] = "dialog";
00212         blob_val(vals[n], dialog);
00213         
00214         cols[++n] = "contact";
00215         string_val(vals[n], s->u.external.contact);
00216         
00217         cols[++n] = "uri";
00218         string_val(vals[n], s->u.external.record_id);
00219         
00220         cols[++n] = "package";
00221         string_val(vals[n], s->u.external.package);
00222         
00223         cols[++n] = "w_uri";
00224         string_val(vals[n], s->u.external.subscriber);
00225 
00226         if (xcap_params2str(&str_xcap_params, &s->xcap_params) != 0) {
00227                 LOG(L_ERR, "Error while serializing xcap params\n");
00228                 str_free_content(&dialog);
00229                 return -1;
00230         }
00231         cols[++n] = "xcap_params";
00232         blob_val(vals[n], str_xcap_params);
00233         
00234         cols[++n] = "id";
00235         string_val_ex(vals[n], s->dbid, strlen(s->dbid));
00236         
00237         /* insert new record into database */
00238         if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
00239                 LOG(L_ERR, "rls_db_add: Error while inserting subscription\n");
00240                 res = -1;
00241         }
00242         
00243         str_free_content(&dialog);
00244         str_free_content(&str_xcap_params);
00245 
00246         if (res == 0) res = vs_db_add(s);
00247         
00248         return res;
00249 }
00250 
00251 int rls_db_remove(rl_subscription_t *s)
00252 {
00253         db_key_t keys[] = { "id" };
00254         db_op_t ops[] = { OP_EQ };
00255         db_val_t k_vals[] = { 
00256                 { DB_STR, 0, 
00257                         { .str_val = { s: s->dbid, len: strlen(s->dbid) } 
00258                         }
00259                 }
00260         };
00261         
00262         if (!use_db) return 0;
00263         
00264         /* only external subscriptions are stored */
00265         if (s->type != rls_external_subscription) return 0;
00266 
00267         if (rls_dbf.use_table(rls_db, rls_table) < 0) {
00268                 LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
00269                 return -1;
00270         }
00271 
00272         if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
00273                 LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
00274                 return -1;
00275         }
00276         
00277         return vs_db_remove(s);
00278 }
00279 
00280 int rls_db_update(rl_subscription_t *s)
00281 {
00282         db_key_t cols[20];
00283         db_val_t vals[20];
00284         str_t dialog = STR_NULL;
00285         str_t str_xcap_params = STR_NULL;
00286         int n = -1;
00287         int res = 0;
00288         time_t t;
00289         db_key_t keys[] = { "id" };
00290         db_op_t ops[] = { OP_EQ };
00291         db_val_t k_vals[] = { 
00292                 { DB_STR, 0, 
00293                         { .str_val = { s: s->dbid, len: strlen(s->dbid) } 
00294                         }
00295                 }
00296         };
00297 
00298         if (!use_db) return 0;
00299         
00300         /* only external subscriptions are stored */
00301         if (s->type != rls_external_subscription) return 0;
00302 
00303         if (rls_dbf.use_table(rls_db, rls_table) < 0) {
00304                 LOG(L_ERR, "rls_db_add: Error in use_table\n");
00305                 return -1;
00306         }
00307         
00308         cols[++n] = "doc_version";
00309         int_val(vals[n], s->doc_version);
00310         
00311         cols[++n] = "status";
00312         int_val(vals[n], s->u.external.status);
00313         
00314         t = time(NULL);
00315         t += rls_subscription_expires_in(s);
00316         cols[++n] = "expires";
00317         time_val(vals[n], t);
00318         
00319         if (dlg_func.dlg2str(s->u.external.dialog, &dialog) != 0) {     
00320                 LOG(L_ERR, "Error while serializing dialog\n");
00321                 return -1;
00322         }
00323         cols[++n] = "dialog";
00324         blob_val(vals[n], dialog);
00325         
00326         cols[++n] = "contact";
00327         string_val(vals[n], s->u.external.contact);
00328         
00329         cols[++n] = "uri";
00330         string_val(vals[n], s->u.external.record_id);
00331         
00332         cols[++n] = "package";
00333         string_val(vals[n], s->u.external.package);
00334         
00335         cols[++n] = "w_uri";
00336         string_val(vals[n], s->u.external.subscriber);
00337         
00338         if (xcap_params2str(&str_xcap_params, &s->xcap_params) != 0) {
00339                 LOG(L_ERR, "Error while serializing xcap params\n");
00340                 str_free_content(&dialog);
00341                 return -1;
00342         }
00343         cols[++n] = "xcap_params";
00344         blob_val(vals[n], str_xcap_params);
00345         
00346         if (rls_dbf.update(rls_db, keys, ops, k_vals, 
00347                                 cols, vals, 1, n + 1) < 0) {
00348                 LOG(L_ERR, "rls_db_add: Error while inserting subscription\n");
00349                 res = -1;
00350         }
00351         
00352         str_free_content(&dialog);
00353         str_free_content(&str_xcap_params);
00354 
00355         return vs_db_update(s);
00356 }
00357 
00358 /* ------------- Loading ------------- */
00359 
00360 #define get_str_val(rvi,dst)    do{if(!rvi.nul){dst.s=(char*)rvi.val.string_val;dst.len=strlen(dst.s);}}while(0)
00361 #define get_blob_val(rvi,dst)   do{if(!rvi.nul){dst=rvi.val.blob_val;}else dst.len=0;}while(0)
00362 #define get_time_val(rvi,dst)   do{if(!rvi.nul){dst=rvi.val.time_val;}}while(0)
00363 #define get_int_val(rvi,dst)    do{if(!rvi.nul){dst=rvi.val.int_val;}else dst=0;}while(0)
00364 
00365 static dlg_t *dlg2str(str_t *s)
00366 {
00367         dlg_t *dlg = (dlg_t*)mem_alloc(sizeof(*dlg));
00368         if (!dlg) LOG(L_ERR, "Can't allocate dialog\n");
00369         else {
00370                 if (dlg_func.str2dlg(s, dlg) != 0) {    
00371                         LOG(L_ERR, "Error while deserializing dialog\n");
00372                         mem_free(dlg);
00373                         dlg = NULL;
00374                 }
00375         }
00376         return dlg;
00377 }
00378 
00379 int db_load_vs_names(db_con_t *rls_db, virtual_subscription_t *vs)
00380 {
00381         int i, r = 0;
00382         db_res_t *res = NULL;
00383         db_key_t result_cols[] = { 
00384                 "name", "lang"
00385         };
00386         db_key_t keys[] = { "id" };
00387         db_op_t ops[] = { OP_EQ };
00388         db_val_t k_vals[] = { 
00389                 { DB_STR, 0, 
00390                         { .str_val = { s: vs->dbid, len: strlen(vs->dbid) } } 
00391                 } 
00392         };
00393 
00394         if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
00395                 LOG(L_ERR, "vs_load_vs_names: Error in use_table\n");
00396                 return -1;
00397         }
00398 
00399         if (rls_dbf.query (rls_db, keys,ops, k_vals,
00400                         result_cols, 1, sizeof(result_cols) / sizeof(db_key_t), 
00401                         0, &res) < 0) {
00402                 LOG(L_ERR, "db_load_vs_names: Error while querying vs names\n");
00403                 r = -1;
00404                 res = NULL;
00405         }
00406         if (res) {
00407                 for (i = 0; i < res->n; i++) {
00408                         db_row_t *row = &res->rows[i];
00409                         db_val_t *row_vals = ROW_VALUES(row);
00410                         str name = STR_NULL;
00411                         str lang = STR_NULL;
00412 
00413                         get_str_val(row_vals[0], name);
00414                         get_str_val(row_vals[1], lang);
00415         
00416                         DEBUG_LOG("     adding name %.*s\n", FMT_STR(name));
00417                         vs_add_display_name(vs, name.s, lang.s);
00418                 }
00419 
00420                 rls_dbf.free_result(rls_db, res);
00421         }
00422         
00423         return r;
00424 }
00425 
00426 int db_load_vs(db_con_t *rls_db, rl_subscription_t *s)
00427 {
00428         int i, r = 0;
00429         db_res_t *res = NULL;
00430         virtual_subscription_t *vs;
00431         db_key_t result_cols[] = { 
00432                 "id", "uri"
00433         };
00434         db_key_t keys[] = { "rls_id" };
00435         db_op_t ops[] = { OP_EQ };
00436         db_val_t k_vals[] = { 
00437                 { DB_STR, 0, 
00438                         { .str_val = { s: s->dbid, len: strlen(s->dbid) } } 
00439                 } 
00440         };
00441 
00442         if (rls_dbf.use_table(rls_db, vs_table) < 0) {
00443                 LOG(L_ERR, "vs_load_vs: Error in use_table\n");
00444                 return -1;
00445         }
00446 
00447         if (rls_dbf.query (rls_db, keys,ops, k_vals,
00448                         result_cols, 1, sizeof(result_cols) / sizeof(db_key_t), 
00449                         0, &res) < 0) {
00450                 LOG(L_ERR, "db_load_vs: Error while querying presentity\n");
00451                 r = -1;
00452                 res = NULL;
00453         }
00454         if (res) {
00455                 for (i = 0; i < res->n; i++) {
00456                         db_row_t *row = &res->rows[i];
00457                         db_val_t *row_vals = ROW_VALUES(row);
00458                         str id = STR_NULL;
00459                         str uri = STR_NULL;
00460 
00461                         get_str_val(row_vals[0], id);
00462                         get_str_val(row_vals[1], uri);
00463                         
00464                         r = vs_create(&uri, &vs, NULL, s, max_list_nesting_level) | r;
00465                         if ((r != 0) || (!vs)) { r = -1; break; }
00466                         
00467                         strcpy(vs->dbid, id.s);
00468                         DEBUG_LOG("  created VS to %.*s\n", FMT_STR(uri));
00469                 
00470                         ptr_vector_add(&s->vs, vs);
00471                         
00472                         db_load_vs_names(rls_db, vs);   
00473                 }
00474 
00475                 rls_dbf.free_result(rls_db, res);
00476         }
00477         
00478         return r;
00479 }
00480 
00481 int db_load_rls()
00482 {
00483         /* this function may be called from mod_init, thus can not work
00484          * with DB connection opened from child_init */
00485         db_con_t* rls_db = NULL; /* own database connection handle */
00486         int i, r = 0;
00487         rl_subscription_t *s;
00488         db_res_t *res = NULL;
00489         db_key_t result_cols[] = { 
00490                 "id", "doc_version", "dialog",
00491                 "expires", "status", "contact",
00492                 "uri", "package", "w_uri",
00493                 "xcap_params"
00494         };
00495 
00496         if (!use_db) return 0;
00497 
00498         DEBUG_LOG("loading rls from db\n");
00499 
00500         /* open own database connection */
00501         if (rls_dbf.init) rls_db = rls_dbf.init(db_url);
00502         if (!rls_db) {
00503                 LOG(L_ERR, "db_load_rls: Error while connecting database\n");
00504                 return -1;
00505         }
00506 
00507         if (rls_dbf.use_table(rls_db, rls_table) < 0) {
00508                 LOG(L_ERR, "rls_load_rls: Error in use_table\n");
00509                 return -1;
00510         }
00511 
00512         if (rls_dbf.query (rls_db, NULL, NULL, NULL,
00513                         result_cols, 0, sizeof(result_cols) / sizeof(db_key_t), 
00514                         0, &res) < 0) {
00515                 LOG(L_ERR, "db_load_rls: Error while querying presentity\n");
00516                 r = -1;
00517                 res = NULL;
00518         }
00519         if (res) {
00520                 for (i = 0; i < res->n; i++) {
00521                         db_row_t *row = &res->rows[i];
00522                         db_val_t *row_vals = ROW_VALUES(row);
00523                         str id = STR_NULL;
00524                         str contact = STR_NULL;
00525                         str dialog = STR_NULL;
00526                         str xcap_params = STR_NULL;
00527                         str uri = STR_NULL;
00528                         str package = STR_NULL;
00529                         str w_uri = STR_NULL;
00530                         subscription_status_t status;
00531                         time_t expires = 0;
00532                         int expires_after;
00533                         dlg_t *dlg = NULL;
00534 
00535                         s = rls_alloc_subscription(rls_external_subscription);
00536                         if (!s) { r = -1; break; }
00537                 
00538                         get_str_val(row_vals[0], id);
00539                         strcpy(s->dbid, id.s);
00540                         get_int_val(row_vals[1], s->doc_version);
00541                         get_blob_val(row_vals[2], dialog);
00542                         get_time_val(row_vals[3], expires);
00543                         get_int_val(row_vals[4], status);
00544                         get_str_val(row_vals[5], contact);
00545                         get_str_val(row_vals[6], uri);
00546                         get_str_val(row_vals[7], package);
00547                         get_str_val(row_vals[8], w_uri);
00548                         get_blob_val(row_vals[9], xcap_params);
00549                         if (expires != 0) expires_after = expires - time(NULL);
00550                         else expires_after = 0;
00551                         dlg = dlg2str(&dialog);
00552                         sm_init_subscription_nolock_ex(rls_manager, &s->u.external, 
00553                                         dlg,
00554                                         status,
00555                                         &contact,
00556                                         &uri,
00557                                         &package,
00558                                         &w_uri,
00559                                         expires_after,
00560                                         s);
00561                         DEBUG_LOG("  created RLS to %.*s from %.*s\n", 
00562                                         FMT_STR(uri), FMT_STR(w_uri));
00563 
00564                         if (str2xcap_params(&s->xcap_params, &xcap_params) < 0) {
00565                                 ERR("can't set xcap params\n");
00566                                 rls_free(s);
00567                                 s = 0;
00568                                 r = -1;
00569                                 break;
00570                         }
00571                 
00572                         /* load virtual subscriptions */
00573                         db_load_vs(rls_db, s);  
00574                 }
00575 
00576                 rls_dbf.free_result(rls_db, res);
00577         }
00578         
00579         /* close db connection */
00580         if (rls_dbf.close) rls_dbf.close(rls_db);
00581 
00582         DEBUG_LOG("rls loaded\n");
00583 
00584         return r;
00585 }
00586