db_rls.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. #include <time.h>
  2. #include <cds/logger.h>
  3. #include "rl_subscription.h"
  4. #include "rls_mod.h"
  5. char *rls_table = "rls_subscription";
  6. char *vs_table = "rls_vs";
  7. char *vs_names_table = "rls_vs_names";
  8. /* generate ID for given data */
  9. void generate_db_id(db_id_t *id, void *data)
  10. {
  11. if (id) {
  12. snprintf(*id, sizeof(*id), "%px%xx%x",
  13. data, (int)time(NULL), rand());
  14. /* DEBUG_LOG("generated DB ID = %s\n", *id); */
  15. }
  16. }
  17. #define string_val(v,s) (v).type = DB_STR; \
  18. (v).val.str_val=s; \
  19. (v).nul=(s.len == 0);
  20. #define int_val(v,i) (v).type = DB_INT; \
  21. (v).val.int_val=i;\
  22. (v).nul=0;
  23. #define time_val(v,t) (v).type = DB_DATETIME; \
  24. (v).val.time_val=t;\
  25. (v).nul=0;
  26. #define string_val_ex(v,str,l) (v).type = DB_STR; \
  27. (v).val.str_val.s=str; \
  28. (v).val.str_val.len=l; \
  29. (v).nul=0;
  30. #define blob_val(v,str) (v).type = DB_BLOB; \
  31. (v).val.blob_val=str; \
  32. (v).nul=0;
  33. /* ------------- virtual subscriptions ------------- */
  34. static int virtual_subscription_db_add(virtual_subscription_t *vs, rl_subscription_t *s)
  35. {
  36. db_key_t cols[20];
  37. db_val_t vals[20];
  38. int n = -1;
  39. int i, cnt;
  40. vs_display_name_t *dn;
  41. DEBUG_LOG("storing into database\n");
  42. if (rls_dbf.use_table(rls_db, vs_table) < 0) {
  43. LOG(L_ERR, "vsub_db_add: Error in use_table\n");
  44. return -1;
  45. }
  46. cols[++n] = "uri";
  47. string_val(vals[n], vs->uri);
  48. cols[++n] = "id";
  49. string_val_ex(vals[n], vs->dbid, strlen(vs->dbid));
  50. cols[++n] = "rls_id";
  51. string_val_ex(vals[n], s->dbid, strlen(s->dbid));
  52. /* insert new record into database */
  53. if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
  54. LOG(L_ERR, "vsub_db_add: Error while inserting virtual subscription\n");
  55. return -1;
  56. }
  57. /* store display names */
  58. cnt = vector_size(&vs->display_names);
  59. for (i = 0; i < cnt; i++) {
  60. if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
  61. LOG(L_ERR, "vsub_db_add (names): Error in use_table\n");
  62. return -1;
  63. }
  64. dn = vector_get_ptr(&vs->display_names, i);
  65. if (!dn) continue;
  66. n = -1;
  67. cols[++n] = "id";
  68. string_val_ex(vals[n], vs->dbid, strlen(vs->dbid));
  69. cols[++n] = "name";
  70. string_val(vals[n], dn->name);
  71. cols[++n] = "lang";
  72. string_val(vals[n], dn->lang);
  73. if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
  74. LOG(L_ERR, "vsub_db_add: Error while inserting name\n");
  75. return -1;
  76. }
  77. }
  78. return 0;
  79. }
  80. static int vs_db_add(rl_subscription_t *s)
  81. {
  82. int i, cnt;
  83. int res = 0;
  84. virtual_subscription_t *vs;
  85. cnt = ptr_vector_size(&s->vs);
  86. for (i = 0; i < cnt; i++) {
  87. vs = ptr_vector_get(&s->vs, i);
  88. if (!vs) continue;
  89. res = virtual_subscription_db_add(vs, s);
  90. if (res != 0) break;
  91. }
  92. return res;
  93. }
  94. static int vs_db_update(rl_subscription_t *s)
  95. {
  96. /* There is nothing to be updated now - may be dialogs for
  97. * external subscriptions and their expirations
  98. * in the future !
  99. *
  100. * Status is newly generated on the other side (in PA)! */
  101. return 0;
  102. }
  103. static int vs_db_remove(rl_subscription_t *s)
  104. {
  105. db_key_t keys[] = { "id" };
  106. db_op_t ops[] = { OP_EQ };
  107. db_val_t k_vals[1];
  108. int i, cnt;
  109. int res = 0;
  110. virtual_subscription_t *vs;
  111. cnt = ptr_vector_size(&s->vs);
  112. for (i = 0; i < cnt; i++) {
  113. vs = ptr_vector_get(&s->vs, i);
  114. if (!vs) continue;
  115. string_val_ex(k_vals[0], vs->dbid, strlen(vs->dbid));
  116. /* remove virtual subscription */
  117. if (rls_dbf.use_table(rls_db, vs_table) < 0) {
  118. LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
  119. res = -1;
  120. }
  121. if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
  122. LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
  123. res = -1;
  124. }
  125. /* remove display names */
  126. if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
  127. LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
  128. res = -1;
  129. }
  130. if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
  131. LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
  132. res = -1;
  133. }
  134. }
  135. return res;
  136. }
  137. /* ------------- rls subscriptions ------------- */
  138. int rls_db_add(rl_subscription_t *s)
  139. {
  140. db_key_t cols[20];
  141. db_val_t vals[20];
  142. str_t dialog = STR_NULL;
  143. str_t str_xcap_params = STR_NULL;
  144. int n = -1;
  145. int res = 0;
  146. time_t t;
  147. if (!use_db) return 0;
  148. /* store only external subscriptions */
  149. if (s->type != rls_external_subscription) return 0;
  150. DEBUG_LOG("storing into database\n");
  151. if (rls_dbf.use_table(rls_db, rls_table) < 0) {
  152. LOG(L_ERR, "rls_db_add: Error in use_table\n");
  153. return -1;
  154. }
  155. cols[++n] = "doc_version";
  156. int_val(vals[n], s->doc_version);
  157. cols[++n] = "status";
  158. int_val(vals[n], s->u.external.status);
  159. t = time(NULL);
  160. t += rls_subscription_expires_in(s);
  161. cols[++n] = "expires";
  162. time_val(vals[n], t);
  163. if (dlg_func.dlg2str(s->u.external.dialog, &dialog) != 0) {
  164. LOG(L_ERR, "Error while serializing dialog\n");
  165. return -1;
  166. }
  167. cols[++n] = "dialog";
  168. blob_val(vals[n], dialog);
  169. cols[++n] = "contact";
  170. string_val(vals[n], s->u.external.contact);
  171. cols[++n] = "uri";
  172. string_val(vals[n], s->u.external.record_id);
  173. cols[++n] = "package";
  174. string_val(vals[n], s->u.external.package);
  175. cols[++n] = "w_uri";
  176. string_val(vals[n], s->u.external.subscriber);
  177. if (xcap_params2str(&str_xcap_params, &s->xcap_params) != 0) {
  178. LOG(L_ERR, "Error while serializing xcap params\n");
  179. str_free_content(&dialog);
  180. return -1;
  181. }
  182. cols[++n] = "xcap_params";
  183. blob_val(vals[n], str_xcap_params);
  184. cols[++n] = "id";
  185. string_val_ex(vals[n], s->dbid, strlen(s->dbid));
  186. /* insert new record into database */
  187. if (rls_dbf.insert(rls_db, cols, vals, n + 1) < 0) {
  188. LOG(L_ERR, "rls_db_add: Error while inserting subscription\n");
  189. res = -1;
  190. }
  191. str_free_content(&dialog);
  192. str_free_content(&str_xcap_params);
  193. if (res == 0) res = vs_db_add(s);
  194. return res;
  195. }
  196. int rls_db_remove(rl_subscription_t *s)
  197. {
  198. db_key_t keys[] = { "id" };
  199. db_op_t ops[] = { OP_EQ };
  200. db_val_t k_vals[] = {
  201. { DB_STR, 0,
  202. { .str_val = { s: s->dbid, len: strlen(s->dbid) }
  203. }
  204. }
  205. };
  206. if (!use_db) return 0;
  207. /* only external subscriptions are stored */
  208. if (s->type != rls_external_subscription) return 0;
  209. if (rls_dbf.use_table(rls_db, rls_table) < 0) {
  210. LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n");
  211. return -1;
  212. }
  213. if (rls_dbf.delete(rls_db, keys, ops, k_vals, 1) < 0) {
  214. LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n");
  215. return -1;
  216. }
  217. return vs_db_remove(s);
  218. }
  219. int rls_db_update(rl_subscription_t *s)
  220. {
  221. db_key_t cols[20];
  222. db_val_t vals[20];
  223. str_t dialog = STR_NULL;
  224. str_t str_xcap_params = STR_NULL;
  225. int n = -1;
  226. int res = 0;
  227. time_t t;
  228. db_key_t keys[] = { "id" };
  229. db_op_t ops[] = { OP_EQ };
  230. db_val_t k_vals[] = {
  231. { DB_STR, 0,
  232. { .str_val = { s: s->dbid, len: strlen(s->dbid) }
  233. }
  234. }
  235. };
  236. if (!use_db) return 0;
  237. /* only external subscriptions are stored */
  238. if (s->type != rls_external_subscription) return 0;
  239. if (rls_dbf.use_table(rls_db, rls_table) < 0) {
  240. LOG(L_ERR, "rls_db_add: Error in use_table\n");
  241. return -1;
  242. }
  243. cols[++n] = "doc_version";
  244. int_val(vals[n], s->doc_version);
  245. cols[++n] = "status";
  246. int_val(vals[n], s->u.external.status);
  247. t = time(NULL);
  248. t += rls_subscription_expires_in(s);
  249. cols[++n] = "expires";
  250. time_val(vals[n], t);
  251. if (dlg_func.dlg2str(s->u.external.dialog, &dialog) != 0) {
  252. LOG(L_ERR, "Error while serializing dialog\n");
  253. return -1;
  254. }
  255. cols[++n] = "dialog";
  256. blob_val(vals[n], dialog);
  257. cols[++n] = "contact";
  258. string_val(vals[n], s->u.external.contact);
  259. cols[++n] = "uri";
  260. string_val(vals[n], s->u.external.record_id);
  261. cols[++n] = "package";
  262. string_val(vals[n], s->u.external.package);
  263. cols[++n] = "w_uri";
  264. string_val(vals[n], s->u.external.subscriber);
  265. if (xcap_params2str(&str_xcap_params, &s->xcap_params) != 0) {
  266. LOG(L_ERR, "Error while serializing xcap params\n");
  267. str_free_content(&dialog);
  268. return -1;
  269. }
  270. cols[++n] = "xcap_params";
  271. blob_val(vals[n], str_xcap_params);
  272. if (rls_dbf.update(rls_db, keys, ops, k_vals,
  273. cols, vals, 1, n + 1) < 0) {
  274. LOG(L_ERR, "rls_db_add: Error while inserting subscription\n");
  275. res = -1;
  276. }
  277. str_free_content(&dialog);
  278. str_free_content(&str_xcap_params);
  279. return vs_db_update(s);
  280. }
  281. /* ------------- Loading ------------- */
  282. #define get_str_val(rvi,dst) do{if(!rvi.nul){dst.s=(char*)rvi.val.string_val;dst.len=strlen(dst.s);}}while(0)
  283. #define get_blob_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.blob_val;}else dst.len=0;}while(0)
  284. #define get_time_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.time_val;}}while(0)
  285. #define get_int_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.int_val;}else dst=0;}while(0)
  286. static dlg_t *dlg2str(str_t *s)
  287. {
  288. dlg_t *dlg = (dlg_t*)mem_alloc(sizeof(*dlg));
  289. if (!dlg) LOG(L_ERR, "Can't allocate dialog\n");
  290. else {
  291. if (dlg_func.str2dlg(s, dlg) != 0) {
  292. LOG(L_ERR, "Error while deserializing dialog\n");
  293. mem_free(dlg);
  294. dlg = NULL;
  295. }
  296. }
  297. return dlg;
  298. }
  299. int db_load_vs_names(db_con_t *rls_db, virtual_subscription_t *vs)
  300. {
  301. int i, r = 0;
  302. db_res_t *res = NULL;
  303. db_key_t result_cols[] = {
  304. "name", "lang"
  305. };
  306. db_key_t keys[] = { "id" };
  307. db_op_t ops[] = { OP_EQ };
  308. db_val_t k_vals[] = {
  309. { DB_STR, 0,
  310. { .str_val = { s: vs->dbid, len: strlen(vs->dbid) } }
  311. }
  312. };
  313. if (rls_dbf.use_table(rls_db, vs_names_table) < 0) {
  314. LOG(L_ERR, "vs_load_vs_names: Error in use_table\n");
  315. return -1;
  316. }
  317. if (rls_dbf.query (rls_db, keys,ops, k_vals,
  318. result_cols, 1, sizeof(result_cols) / sizeof(db_key_t),
  319. 0, &res) < 0) {
  320. LOG(L_ERR, "db_load_vs_names: Error while querying vs names\n");
  321. r = -1;
  322. res = NULL;
  323. }
  324. if (res) {
  325. for (i = 0; i < res->n; i++) {
  326. db_row_t *row = &res->rows[i];
  327. db_val_t *row_vals = ROW_VALUES(row);
  328. str name = STR_NULL;
  329. str lang = STR_NULL;
  330. get_str_val(row_vals[0], name);
  331. get_str_val(row_vals[1], lang);
  332. DEBUG_LOG(" adding name %.*s\n", FMT_STR(name));
  333. vs_add_display_name(vs, name.s, lang.s);
  334. }
  335. rls_dbf.free_result(rls_db, res);
  336. }
  337. return r;
  338. }
  339. int db_load_vs(db_con_t *rls_db, rl_subscription_t *s)
  340. {
  341. int i, r = 0;
  342. db_res_t *res = NULL;
  343. virtual_subscription_t *vs;
  344. db_key_t result_cols[] = {
  345. "id", "uri"
  346. };
  347. db_key_t keys[] = { "rls_id" };
  348. db_op_t ops[] = { OP_EQ };
  349. db_val_t k_vals[] = {
  350. { DB_STR, 0,
  351. { .str_val = { s: s->dbid, len: strlen(s->dbid) } }
  352. }
  353. };
  354. if (rls_dbf.use_table(rls_db, vs_table) < 0) {
  355. LOG(L_ERR, "vs_load_vs: Error in use_table\n");
  356. return -1;
  357. }
  358. if (rls_dbf.query (rls_db, keys,ops, k_vals,
  359. result_cols, 1, sizeof(result_cols) / sizeof(db_key_t),
  360. 0, &res) < 0) {
  361. LOG(L_ERR, "db_load_vs: Error while querying presentity\n");
  362. r = -1;
  363. res = NULL;
  364. }
  365. if (res) {
  366. for (i = 0; i < res->n; i++) {
  367. db_row_t *row = &res->rows[i];
  368. db_val_t *row_vals = ROW_VALUES(row);
  369. str id = STR_NULL;
  370. str uri = STR_NULL;
  371. get_str_val(row_vals[0], id);
  372. get_str_val(row_vals[1], uri);
  373. r = vs_create(&uri, &vs, NULL, s, max_list_nesting_level) | r;
  374. if ((r != 0) || (!vs)) { r = -1; break; }
  375. strcpy(vs->dbid, id.s);
  376. DEBUG_LOG(" created VS to %.*s\n", FMT_STR(uri));
  377. ptr_vector_add(&s->vs, vs);
  378. db_load_vs_names(rls_db, vs);
  379. }
  380. rls_dbf.free_result(rls_db, res);
  381. }
  382. return r;
  383. }
  384. int db_load_rls()
  385. {
  386. /* this function may be called from mod_init, thus can not work
  387. * with DB connection opened from child_init */
  388. db_con_t* rls_db = NULL; /* own database connection handle */
  389. int i, r = 0;
  390. rl_subscription_t *s;
  391. db_res_t *res = NULL;
  392. db_key_t result_cols[] = {
  393. "id", "doc_version", "dialog",
  394. "expires", "status", "contact",
  395. "uri", "package", "w_uri",
  396. "xcap_params"
  397. };
  398. if (!use_db) return 0;
  399. DEBUG_LOG("loading rls from db\n");
  400. /* open own database connection */
  401. if (rls_dbf.init) rls_db = rls_dbf.init(db_url);
  402. if (!rls_db) {
  403. LOG(L_ERR, "db_load_rls: Error while connecting database\n");
  404. return -1;
  405. }
  406. if (rls_dbf.use_table(rls_db, rls_table) < 0) {
  407. LOG(L_ERR, "rls_load_rls: Error in use_table\n");
  408. return -1;
  409. }
  410. if (rls_dbf.query (rls_db, NULL, NULL, NULL,
  411. result_cols, 0, sizeof(result_cols) / sizeof(db_key_t),
  412. 0, &res) < 0) {
  413. LOG(L_ERR, "db_load_rls: Error while querying presentity\n");
  414. r = -1;
  415. res = NULL;
  416. }
  417. if (res) {
  418. for (i = 0; i < res->n; i++) {
  419. db_row_t *row = &res->rows[i];
  420. db_val_t *row_vals = ROW_VALUES(row);
  421. str id = STR_NULL;
  422. str contact = STR_NULL;
  423. str dialog = STR_NULL;
  424. str xcap_params = STR_NULL;
  425. str uri = STR_NULL;
  426. str package = STR_NULL;
  427. str w_uri = STR_NULL;
  428. subscription_status_t status;
  429. time_t expires = 0;
  430. int expires_after;
  431. dlg_t *dlg = NULL;
  432. s = rls_alloc_subscription(rls_external_subscription);
  433. if (!s) { r = -1; break; }
  434. get_str_val(row_vals[0], id);
  435. strcpy(s->dbid, id.s);
  436. get_int_val(row_vals[1], s->doc_version);
  437. get_blob_val(row_vals[2], dialog);
  438. get_time_val(row_vals[3], expires);
  439. get_int_val(row_vals[4], status);
  440. get_str_val(row_vals[5], contact);
  441. get_str_val(row_vals[6], uri);
  442. get_str_val(row_vals[7], package);
  443. get_str_val(row_vals[8], w_uri);
  444. get_blob_val(row_vals[9], xcap_params);
  445. if (expires != 0) expires_after = expires - time(NULL);
  446. else expires_after = 0;
  447. dlg = dlg2str(&dialog);
  448. sm_init_subscription_nolock_ex(rls_manager, &s->u.external,
  449. dlg,
  450. status,
  451. &contact,
  452. &uri,
  453. &package,
  454. &w_uri,
  455. expires_after,
  456. s);
  457. DEBUG_LOG(" created RLS to %.*s from %.*s\n",
  458. FMT_STR(uri), FMT_STR(w_uri));
  459. if (str2xcap_params(&s->xcap_params, &xcap_params) < 0) {
  460. ERR("can't set xcap params\n");
  461. rls_free(s);
  462. s = 0;
  463. r = -1;
  464. break;
  465. }
  466. /* load virtual subscriptions */
  467. db_load_vs(rls_db, s);
  468. }
  469. rls_dbf.free_result(rls_db, res);
  470. }
  471. /* close db connection */
  472. if (rls_dbf.close) rls_dbf.close(rls_db);
  473. DEBUG_LOG("rls loaded\n");
  474. return r;
  475. }