mohq_db.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2013 Robert Boisvert
  5. *
  6. * This file is part of the mohqueue module for sip-router, a free SIP server.
  7. *
  8. * The mohqueue module is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * The mohqueue module is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. */
  23. #include "mohq.h"
  24. #include "mohq_db.h"
  25. #include "mohq_funcs.h"
  26. /**********
  27. * mohqueue definitions
  28. **********/
  29. str MOHQCSTR_ID = STR_STATIC_INIT ("id");
  30. str MOHQCSTR_URI = STR_STATIC_INIT ("uri");
  31. str MOHQCSTR_MDIR = STR_STATIC_INIT ("mohdir");
  32. str MOHQCSTR_MFILE = STR_STATIC_INIT ("mohfile");
  33. str MOHQCSTR_NAME = STR_STATIC_INIT ("name");
  34. str MOHQCSTR_DEBUG = STR_STATIC_INIT ("debug");
  35. static str *mohq_columns [] =
  36. {
  37. &MOHQCSTR_ID,
  38. &MOHQCSTR_URI,
  39. &MOHQCSTR_MDIR,
  40. &MOHQCSTR_MFILE,
  41. &MOHQCSTR_NAME,
  42. &MOHQCSTR_DEBUG,
  43. NULL
  44. };
  45. /**********
  46. * mohqcalls definitions
  47. **********/
  48. str CALLCSTR_CALL = STR_STATIC_INIT ("call_id");
  49. str CALLCSTR_CNTCT = STR_STATIC_INIT ("call_contact");
  50. str CALLCSTR_FROM = STR_STATIC_INIT ("call_from");
  51. str CALLCSTR_MOHQ = STR_STATIC_INIT ("mohq_id");
  52. str CALLCSTR_STATE = STR_STATIC_INIT ("call_status");
  53. str CALLCSTR_TIME = STR_STATIC_INIT ("call_time");
  54. static str *call_columns [] =
  55. {
  56. &CALLCSTR_STATE,
  57. &CALLCSTR_CALL,
  58. &CALLCSTR_MOHQ,
  59. &CALLCSTR_FROM,
  60. &CALLCSTR_CNTCT,
  61. &CALLCSTR_TIME,
  62. NULL
  63. };
  64. /**********
  65. * local function declarations
  66. **********/
  67. void set_call_key (db_key_t *, int, int);
  68. void set_call_val (db_val_t *, int, int, void *);
  69. /**********
  70. * local functions
  71. **********/
  72. /**********
  73. * Fill Call Keys
  74. *
  75. * INPUT:
  76. * Arg (1) = row pointer
  77. * Arg (2) = column count
  78. * OUTPUT: none
  79. **********/
  80. void fill_call_keys (db_key_t *prkeys, int ncnt)
  81. {
  82. int nidx;
  83. for (nidx = 0; nidx < ncnt; nidx++)
  84. { set_call_key (prkeys, nidx, nidx); }
  85. return;
  86. }
  87. /**********
  88. * Fill Call Values
  89. *
  90. * INPUT:
  91. * Arg (1) = row pointer
  92. * Arg (2) = call struct pointer
  93. * Arg (3) = column count
  94. * OUTPUT: none
  95. **********/
  96. void fill_call_vals (db_val_t *prvals, call_lst *pcall, int ncnt)
  97. {
  98. int nstate = pcall->call_state / 100;
  99. set_call_val (prvals, CALLCOL_STATE, CALLCOL_STATE, &nstate);
  100. if (!ncnt)
  101. { return; }
  102. set_call_val (prvals, CALLCOL_MOHQ, CALLCOL_MOHQ, &pcall->pmohq->mohq_id);
  103. set_call_val (prvals, CALLCOL_CALL, CALLCOL_CALL, pcall->call_id);
  104. set_call_val (prvals, CALLCOL_FROM, CALLCOL_FROM, pcall->call_from);
  105. set_call_val (prvals, CALLCOL_CNTCT, CALLCOL_CNTCT, pcall->call_contact);
  106. set_call_val (prvals, CALLCOL_TIME, CALLCOL_TIME, &pcall->call_time);
  107. return;
  108. }
  109. /**********
  110. * Set Call Column Key
  111. *
  112. * INPUT:
  113. * Arg (1) = row pointer
  114. * Arg (2) = column number
  115. * Arg (3) = column id
  116. * OUTPUT: none
  117. **********/
  118. void set_call_key (db_key_t *prkeys, int ncol, int ncolid)
  119. {
  120. prkeys [ncol] = call_columns [ncolid];
  121. return;
  122. }
  123. /**********
  124. * Set Call Column Value
  125. *
  126. * INPUT:
  127. * Arg (1) = row pointer
  128. * Arg (2) = column number
  129. * Arg (3) = column id
  130. * Arg (4) = value pointer
  131. * OUTPUT: none
  132. **********/
  133. void set_call_val (db_val_t *prvals, int ncol, int ncolid, void *pdata)
  134. {
  135. /**********
  136. * fill based on column
  137. **********/
  138. switch (ncolid)
  139. {
  140. case CALLCOL_MOHQ:
  141. case CALLCOL_STATE:
  142. prvals [ncol].val.int_val = *((int *)pdata);
  143. prvals [ncol].type = DB1_INT;
  144. prvals [ncol].nul = 0;
  145. break;
  146. case CALLCOL_CALL:
  147. case CALLCOL_CNTCT:
  148. case CALLCOL_FROM:
  149. prvals [ncol].val.string_val = (char *)pdata;
  150. prvals [ncol].type = DB1_STRING;
  151. prvals [ncol].nul = 0;
  152. break;
  153. case CALLCOL_TIME:
  154. prvals [ncol].val.time_val = *((time_t *)pdata);
  155. prvals [ncol].type = DB1_DATETIME;
  156. prvals [ncol].nul = 0;
  157. break;
  158. }
  159. return;
  160. }
  161. /**********
  162. * external functions
  163. **********/
  164. /**********
  165. * Add Call Record
  166. *
  167. * INPUT:
  168. * Arg (1) = call index
  169. * OUTPUT: none
  170. **********/
  171. void add_call_rec (int ncall_idx)
  172. {
  173. /**********
  174. * o fill column names and values
  175. * o insert new record
  176. **********/
  177. char *pfncname = "add_call_rec: ";
  178. db1_con_t *pconn = mohq_dbconnect ();
  179. if (!pconn)
  180. { return; }
  181. db_func_t *pdb = pmod_data->pdb;
  182. pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
  183. db_key_t prkeys [CALL_COLCNT];
  184. fill_call_keys (prkeys, CALL_COLCNT);
  185. db_val_t prvals [CALL_COLCNT];
  186. call_lst *pcall = &pmod_data->pcall_lst [ncall_idx];
  187. pcall->call_time = time (0);
  188. fill_call_vals (prvals, pcall, CALL_COLCNT);
  189. if (pdb->insert (pconn, prkeys, prvals, CALL_COLCNT) < 0)
  190. {
  191. LM_WARN ("%sUnable to add new row to %s", pfncname,
  192. pmod_data->pcfg->db_ctable.s);
  193. }
  194. mohq_dbdisconnect (pconn);
  195. return;
  196. }
  197. /**********
  198. * Clear Call Records
  199. *
  200. * INPUT:
  201. * Arg (1) = connection pointer
  202. * OUTPUT: none
  203. **********/
  204. void clear_calls (db1_con_t *pconn)
  205. {
  206. /**********
  207. * delete all records
  208. **********/
  209. char *pfncname = "clear_calls: ";
  210. db_func_t *pdb = pmod_data->pdb;
  211. pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
  212. if (pdb->delete (pconn, 0, 0, 0, 0) < 0)
  213. {
  214. LM_WARN ("%sUnable to delete all rows from %s", pfncname,
  215. pmod_data->pcfg->db_ctable.s);
  216. }
  217. return;
  218. }
  219. /**********
  220. * Delete Call Record
  221. *
  222. * INPUT:
  223. * Arg (1) = call pointer
  224. * OUTPUT: none
  225. **********/
  226. void delete_call_rec (call_lst *pcall)
  227. {
  228. /**********
  229. * o setup to delete based on call ID
  230. * o delete record
  231. **********/
  232. char *pfncname = "delete_call_rec: ";
  233. db1_con_t *pconn = mohq_dbconnect ();
  234. if (!pconn)
  235. { return; }
  236. db_func_t *pdb = pmod_data->pdb;
  237. pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
  238. db_key_t prkeys [1];
  239. set_call_key (prkeys, 0, CALLCOL_CALL);
  240. db_val_t prvals [1];
  241. set_call_val (prvals, 0, CALLCOL_CALL, pcall->call_id);
  242. if (pdb->delete (pconn, prkeys, 0, prvals, 1) < 0)
  243. {
  244. LM_WARN ("%sUnable to delete row from %s", pfncname,
  245. pmod_data->pcfg->db_ctable.s);
  246. }
  247. mohq_dbdisconnect (pconn);
  248. return;
  249. }
  250. /**********
  251. * Connect to DB
  252. *
  253. * INPUT: none
  254. * OUTPUT: DB connection pointer; NULL=failed
  255. **********/
  256. db1_con_t *mohq_dbconnect (void)
  257. {
  258. str *pdb_url = &pmod_data->pcfg->db_url;
  259. db1_con_t *pconn = pmod_data->pdb->init (pdb_url);
  260. if (!pconn)
  261. { LM_ERR ("Unable to connect to DB %s", pdb_url->s); }
  262. return pconn;
  263. }
  264. /**********
  265. * Disconnect from DB
  266. *
  267. * INPUT:
  268. * Arg (1) = connection pointer
  269. * OUTPUT: none
  270. **********/
  271. void mohq_dbdisconnect (db1_con_t *pconn)
  272. {
  273. pmod_data->pdb->close (pconn);
  274. return;
  275. }
  276. /**********
  277. * Update Call Record
  278. *
  279. * INPUT:
  280. * Arg (1) = call pointer
  281. * OUTPUT: none
  282. **********/
  283. void update_call_rec (call_lst *pcall)
  284. {
  285. /**********
  286. * o setup to update based on call ID
  287. * o update record
  288. **********/
  289. char *pfncname = "update_call_rec: ";
  290. db1_con_t *pconn = mohq_dbconnect ();
  291. if (!pconn)
  292. { return; }
  293. db_func_t *pdb = pmod_data->pdb;
  294. pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
  295. db_key_t pqkeys [1];
  296. set_call_key (pqkeys, 0, CALLCOL_CALL);
  297. db_val_t pqvals [1];
  298. set_call_val (pqvals, 0, CALLCOL_CALL, pcall->call_id);
  299. db_key_t pukeys [1];
  300. set_call_key (pukeys, 0, CALLCOL_STATE);
  301. db_val_t puvals [1];
  302. fill_call_vals (puvals, pcall, CALLCOL_STATE);
  303. if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
  304. {
  305. LM_WARN ("%sUnable to update row in %s", pfncname,
  306. pmod_data->pcfg->db_ctable.s);
  307. }
  308. mohq_dbdisconnect (pconn);
  309. return;
  310. }
  311. /**********
  312. * Update Debug Record
  313. *
  314. * INPUT:
  315. * Arg (1) = MOH queue pointer
  316. * Arg (2) = debug flag
  317. * OUTPUT: none
  318. **********/
  319. void update_debug (mohq_lst *pqueue, int bdebug)
  320. {
  321. /**********
  322. * o setup to update based on queue name
  323. * o update record
  324. **********/
  325. char *pfncname = "update_debug: ";
  326. db1_con_t *pconn = mohq_dbconnect ();
  327. if (!pconn)
  328. { return; }
  329. db_func_t *pdb = pmod_data->pdb;
  330. pdb->use_table (pconn, &pmod_data->pcfg->db_qtable);
  331. db_key_t pqkeys [1] = { mohq_columns [MOHQCOL_NAME] };
  332. db_val_t pqvals [1];
  333. pqvals->val.string_val = pqueue->mohq_name;
  334. pqvals->type = DB1_STRING;
  335. pqvals->nul = 0;
  336. db_key_t pukeys [1] = { mohq_columns [MOHQCOL_DEBUG] };
  337. db_val_t puvals [1];
  338. puvals->val.int_val = bdebug;
  339. puvals->type = DB1_INT;
  340. puvals->nul = 0;
  341. if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
  342. {
  343. LM_WARN ("%sUnable to update row in %s", pfncname,
  344. pmod_data->pcfg->db_qtable.s);
  345. }
  346. mohq_dbdisconnect (pconn);
  347. return;
  348. }
  349. /**********
  350. * Update Message Queue List
  351. *
  352. * INPUT:
  353. * Arg (1) = connection pointer
  354. * OUTPUT: none
  355. **********/
  356. void update_mohq_lst (db1_con_t *pconn)
  357. {
  358. /**********
  359. * o reset checked flag on all queues
  360. * o read queues from table
  361. **********/
  362. char *pfncname = "update_mohq_lst: ";
  363. if (!pconn)
  364. { return; }
  365. db_func_t *pdb = pmod_data->pdb;
  366. mohq_lst *pqlst = pmod_data->pmohq_lst;
  367. int nidx;
  368. for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
  369. { pqlst [nidx].mohq_flags &= ~MOHQF_CHK; }
  370. pdb->use_table (pconn, &pmod_data->pcfg->db_qtable);
  371. db_key_t prkeys [MOHQ_COLCNT];
  372. for (nidx = 0; nidx < MOHQ_COLCNT; nidx++)
  373. { prkeys [nidx] = mohq_columns [nidx]; }
  374. db1_res_t *presult = NULL;
  375. if (pdb->query (pconn, 0, 0, 0, prkeys, 0, MOHQ_COLCNT, 0, &presult))
  376. {
  377. LM_ERR ("%stable query (%s) failed!", pfncname,
  378. pmod_data->pcfg->db_qtable.s);
  379. return;
  380. }
  381. db_row_t *prows = RES_ROWS (presult);
  382. int nrows = RES_ROW_N (presult);
  383. db_val_t *prowvals = NULL;
  384. char *ptext, *puri;
  385. mohq_lst *pnewlst;
  386. for (nidx = 0; nidx < nrows; nidx++)
  387. {
  388. /**********
  389. * check URI
  390. **********/
  391. prowvals = ROW_VALUES (prows + nidx);
  392. char *pqname = (char *)VAL_STRING (prowvals + MOHQCOL_NAME);
  393. puri = (char *)VAL_STRING (prowvals + MOHQCOL_URI);
  394. struct sip_uri puri_parsed [1];
  395. if (parse_uri (puri, strlen (puri), puri_parsed))
  396. {
  397. LM_ERR ("Queue,Field (%s,%.*s): %s is not a valid URI!", pqname,
  398. STR_FMT (&MOHQCSTR_URI), puri);
  399. continue;
  400. }
  401. /**********
  402. * check MOHDIR
  403. **********/
  404. char *pmohdir;
  405. if (VAL_NULL (prowvals + MOHQCOL_MDIR))
  406. { pmohdir = pmod_data->pcfg->mohdir; }
  407. else
  408. {
  409. pmohdir = (char *)VAL_STRING (prowvals + MOHQCOL_MDIR);
  410. if (!*pmohdir)
  411. { pmohdir = pmod_data->pcfg->mohdir; }
  412. else
  413. {
  414. /**********
  415. * mohdir
  416. * o exists?
  417. * o directory?
  418. **********/
  419. struct stat psb [1];
  420. if (lstat (pmohdir, psb))
  421. {
  422. LM_ERR ("Queue,Field (%s,%.*s): Unable to find %s!", pqname,
  423. STR_FMT (&MOHQCSTR_MDIR), pmohdir);
  424. continue;
  425. }
  426. else
  427. {
  428. if ((psb->st_mode & S_IFMT) != S_IFDIR)
  429. {
  430. LM_ERR ("Queue,Field (%s,%.*s): %s is not a directory!", pqname,
  431. STR_FMT (&MOHQCSTR_MDIR), pmohdir);
  432. continue;
  433. }
  434. }
  435. }
  436. }
  437. /**********
  438. * check for MOH files
  439. **********/
  440. rtpmap **pmohfiles = find_MOH (pmohdir,
  441. (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
  442. if (!pmohfiles [0])
  443. {
  444. LM_ERR ("Queue,Field (%s,%.*s): Unable to find MOH files (%s/%s.*)!",
  445. pqname, STR_FMT (&MOHQCSTR_MDIR), pmohdir,
  446. (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
  447. continue;
  448. }
  449. /**********
  450. * find matching queues
  451. **********/
  452. int bfnd = 0;
  453. int nidx2;
  454. for (nidx2 = 0; nidx2 < pmod_data->mohq_cnt; nidx2++)
  455. {
  456. if (!strcasecmp (pqlst [nidx2].mohq_uri, puri))
  457. {
  458. /**********
  459. * o data the same?
  460. * o mark as found
  461. **********/
  462. if (strcmp (pqlst [nidx2].mohq_mohdir, pmohdir))
  463. {
  464. strcpy (pqlst [nidx2].mohq_mohdir, pmohdir);
  465. LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
  466. STR_FMT (&MOHQCSTR_MDIR));
  467. }
  468. ptext = (char *)VAL_STRING (prowvals + MOHQCOL_MFILE);
  469. if (strcmp (pqlst [nidx2].mohq_mohfile, ptext))
  470. {
  471. strcpy (pqlst [nidx2].mohq_mohfile, ptext);
  472. LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
  473. STR_FMT (&MOHQCSTR_MFILE));
  474. }
  475. ptext = (char *)VAL_STRING (prowvals + MOHQCOL_NAME);
  476. if (strcmp (pqlst [nidx2].mohq_name, ptext))
  477. {
  478. strcpy (pqlst [nidx2].mohq_name, ptext);
  479. LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
  480. STR_FMT (&MOHQCSTR_NAME));
  481. }
  482. int bdebug = VAL_INT (prowvals + MOHQCOL_DEBUG) ? MOHQF_DBG : 0;
  483. if ((pqlst [nidx2].mohq_flags & MOHQF_DBG) != bdebug)
  484. {
  485. if (bdebug)
  486. { pqlst [nidx2].mohq_flags |= MOHQF_DBG; }
  487. else
  488. { pqlst [nidx2].mohq_flags &= ~MOHQF_DBG; }
  489. LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
  490. STR_FMT (&MOHQCSTR_DEBUG));
  491. }
  492. bfnd = -1;
  493. pqlst [nidx2].mohq_flags |= MOHQF_CHK;
  494. break;
  495. }
  496. }
  497. /**********
  498. * add new queue
  499. **********/
  500. if (!bfnd)
  501. {
  502. /**********
  503. * o allocate new list
  504. * o copy old list
  505. * o add new row
  506. * o release old list
  507. * o adjust pointers to new list
  508. **********/
  509. int nsize = pmod_data->mohq_cnt + 1;
  510. pnewlst = (mohq_lst *) shm_malloc (sizeof (mohq_lst) * nsize);
  511. if (!pnewlst)
  512. {
  513. LM_ERR ("%sUnable to allocate shared memory!", pfncname);
  514. return;
  515. }
  516. pmod_data->mohq_cnt = nsize;
  517. if (--nsize)
  518. { memcpy (pnewlst, pqlst, sizeof (mohq_lst) * nsize); }
  519. pnewlst [nsize].mohq_id = prowvals [MOHQCOL_ID].val.int_val;
  520. pnewlst [nsize].mohq_flags = MOHQF_CHK;
  521. strcpy (pnewlst [nsize].mohq_uri, puri);
  522. strcpy (pnewlst [nsize].mohq_mohdir, pmohdir);
  523. strcpy (pnewlst [nsize].mohq_mohfile,
  524. (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
  525. strcpy (pnewlst [nsize].mohq_name,
  526. (char *)VAL_STRING (prowvals + MOHQCOL_NAME));
  527. if (VAL_INT (prowvals + MOHQCOL_DEBUG))
  528. { pnewlst [nsize].mohq_flags |= MOHQF_DBG; }
  529. LM_INFO ("Added new queue (%s)", pnewlst [nsize].mohq_name);
  530. if (nsize)
  531. { shm_free (pmod_data->pmohq_lst); }
  532. pmod_data->pmohq_lst = pnewlst;
  533. pqlst = pnewlst;
  534. }
  535. }
  536. /**********
  537. * find deleted queues
  538. **********/
  539. for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
  540. {
  541. /**********
  542. * o exists?
  543. * o if not last, replace current with last queue
  544. **********/
  545. if (pqlst [nidx].mohq_flags & MOHQF_CHK)
  546. { continue; }
  547. LM_INFO ("Removed queue (%s)", pqlst [nidx].mohq_name);
  548. if (nidx != (pmod_data->mohq_cnt - 1))
  549. {
  550. memcpy (&pqlst [nidx], &pqlst [pmod_data->mohq_cnt - 1],
  551. sizeof (mohq_lst));
  552. }
  553. --pmod_data->mohq_cnt;
  554. --nidx;
  555. }
  556. return;
  557. }