mongodb_client.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
  3. *
  4. * This file is part of Kamailio, a free SIP server.
  5. *
  6. * Kamailio is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version
  10. *
  11. * Kamailio is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/time.h>
  26. #include <stdarg.h>
  27. #include "../../mem/mem.h"
  28. #include "../../dprint.h"
  29. #include "../../hashes.h"
  30. #include "../../ut.h"
  31. #include "mongodb_client.h"
  32. #include "api.h"
  33. static mongodbc_server_t *_mongodbc_srv_list=NULL;
  34. static mongodbc_reply_t *_mongodbc_rpl_list=NULL;
  35. void mongodbc_destroy_reply(mongodbc_reply_t *rpl);
  36. /**
  37. *
  38. */
  39. int mongodbc_init(void)
  40. {
  41. mongodbc_server_t *rsrv=NULL;
  42. if(_mongodbc_srv_list==NULL)
  43. {
  44. LM_ERR("no mongodb servers defined\n");
  45. return -1;
  46. }
  47. for(rsrv=_mongodbc_srv_list; rsrv; rsrv=rsrv->next)
  48. {
  49. if(rsrv->uri==NULL || rsrv->uri->len<=0) {
  50. LM_ERR("no uri for server: %.*s\n",
  51. rsrv->sname->len, rsrv->sname->s);
  52. return -1;
  53. }
  54. rsrv->client = mongoc_client_new (rsrv->uri->s);
  55. if(rsrv->client==NULL) {
  56. LM_ERR("failed to connect to: %.*s (%.*s)\n",
  57. rsrv->sname->len, rsrv->sname->s,
  58. rsrv->uri->len, rsrv->uri->s);
  59. return -1;
  60. }
  61. }
  62. return 0;
  63. }
  64. /**
  65. *
  66. */
  67. int mongodbc_destroy(void)
  68. {
  69. mongodbc_reply_t *rpl, *next_rpl;
  70. mongodbc_server_t *rsrv=NULL;
  71. mongodbc_server_t *rsrv1=NULL;
  72. rpl = _mongodbc_rpl_list;
  73. while(rpl != NULL)
  74. {
  75. next_rpl = rpl->next;
  76. mongodbc_destroy_reply(rpl);
  77. pkg_free(rpl);
  78. rpl = next_rpl;
  79. }
  80. _mongodbc_rpl_list = NULL;
  81. if(_mongodbc_srv_list==NULL)
  82. return -1;
  83. rsrv=_mongodbc_srv_list;
  84. while(rsrv!=NULL)
  85. {
  86. rsrv1 = rsrv;
  87. rsrv=rsrv->next;
  88. if(rsrv1->client!=NULL)
  89. mongoc_client_destroy(rsrv1->client);
  90. free_params(rsrv1->attrs);
  91. pkg_free(rsrv1);
  92. }
  93. _mongodbc_srv_list = NULL;
  94. return 0;
  95. }
  96. /**
  97. *
  98. */
  99. int mongodbc_add_server(char *spec)
  100. {
  101. param_t *pit=NULL;
  102. param_hooks_t phooks;
  103. mongodbc_server_t *rsrv=NULL;
  104. str s;
  105. s.s = spec;
  106. s.len = strlen(spec);
  107. if(s.s[s.len-1]==';')
  108. s.len--;
  109. if (parse_params(&s, CLASS_ANY, &phooks, &pit)<0)
  110. {
  111. LM_ERR("failed parsing params value\n");
  112. goto error;
  113. }
  114. rsrv = (mongodbc_server_t*)pkg_malloc(sizeof(mongodbc_server_t));
  115. if(rsrv==NULL)
  116. {
  117. LM_ERR("no more pkg\n");
  118. goto error;
  119. }
  120. memset(rsrv, 0, sizeof(mongodbc_server_t));
  121. rsrv->attrs = pit;
  122. for (pit = rsrv->attrs; pit; pit=pit->next)
  123. {
  124. if(pit->name.len==4 && strncmp(pit->name.s, "name", 4)==0) {
  125. rsrv->sname = &pit->body;
  126. rsrv->hname = get_hash1_raw(rsrv->sname->s, rsrv->sname->len);
  127. } else if(pit->name.len==3 && strncmp(pit->name.s, "uri", 3)==0) {
  128. rsrv->uri = &pit->body;
  129. if(rsrv->uri->s[rsrv->uri->len]!='\0') rsrv->uri->s[rsrv->uri->len]='\0';
  130. }
  131. }
  132. if(rsrv->sname==NULL || rsrv->uri==NULL)
  133. {
  134. LM_ERR("no server name or uri\n");
  135. goto error;
  136. }
  137. LM_DBG("added server[%.*s]=%.*s\n",
  138. rsrv->sname->len, rsrv->sname->s,
  139. rsrv->uri->len, rsrv->uri->s);
  140. rsrv->next = _mongodbc_srv_list;
  141. _mongodbc_srv_list = rsrv;
  142. return 0;
  143. error:
  144. if(pit!=NULL)
  145. free_params(pit);
  146. if(rsrv!=NULL)
  147. pkg_free(rsrv);
  148. return -1;
  149. }
  150. /**
  151. *
  152. */
  153. mongodbc_server_t *mongodbc_get_server(str *name)
  154. {
  155. mongodbc_server_t *rsrv=NULL;
  156. unsigned int hname;
  157. hname = get_hash1_raw(name->s, name->len);
  158. rsrv=_mongodbc_srv_list;
  159. while(rsrv!=NULL)
  160. {
  161. if(rsrv->hname==hname && rsrv->sname->len==name->len
  162. && strncmp(rsrv->sname->s, name->s, name->len)==0)
  163. return rsrv;
  164. rsrv=rsrv->next;
  165. }
  166. return NULL;
  167. }
  168. /**
  169. *
  170. */
  171. int mongodbc_reconnect_server(mongodbc_server_t *rsrv)
  172. {
  173. mongoc_init();
  174. if(rsrv->client!=NULL)
  175. mongoc_client_destroy(rsrv->client);
  176. rsrv->client = mongoc_client_new (rsrv->uri->s);
  177. if(rsrv->client!=NULL) {
  178. LM_ERR("failed to connect to: %.*s (%.*s)\n",
  179. rsrv->sname->len, rsrv->sname->s,
  180. rsrv->uri->len, rsrv->uri->s);
  181. return -1;
  182. }
  183. return 0;
  184. }
  185. /**
  186. *
  187. */
  188. int mongodbc_exec_cmd(str *srv, str *dname, str *cname, str *cmd, str *res, int emode)
  189. {
  190. mongodbc_server_t *rsrv=NULL;
  191. mongodbc_reply_t *rpl=NULL;
  192. bson_error_t error;
  193. bson_t command;
  194. bson_t reply;
  195. const bson_t *cdoc;
  196. char c;
  197. int nres;
  198. int ret;
  199. if(srv==NULL || cmd==NULL || res==NULL)
  200. {
  201. LM_ERR("invalid parameters");
  202. goto error_exec;
  203. }
  204. if(srv->len==0 || res->len==0 || cmd->len==0)
  205. {
  206. LM_ERR("invalid parameters");
  207. goto error_exec;
  208. }
  209. rsrv = mongodbc_get_server(srv);
  210. if(rsrv==NULL)
  211. {
  212. LM_ERR("no mongodb server found: %.*s\n", srv->len, srv->s);
  213. goto error_exec;
  214. }
  215. if(rsrv->client==NULL)
  216. {
  217. if(mongodbc_reconnect_server(rsrv)<0) {
  218. LM_ERR("no mongodb context for server: %.*s\n", srv->len, srv->s);
  219. goto error_exec;
  220. }
  221. }
  222. rpl = mongodbc_get_reply(res);
  223. if(rpl==NULL)
  224. {
  225. LM_ERR("no mongodb reply id found: %.*s\n", res->len, res->s);
  226. goto error_exec;
  227. }
  228. mongodbc_destroy_reply(rpl);
  229. rpl->collection = mongoc_client_get_collection (rsrv->client, dname->s, cname->s);
  230. LM_DBG("trying to execute: [[%.*s]]\n", cmd->len, cmd->s);
  231. c = cmd->s[cmd->len];
  232. cmd->s[cmd->len] = '\0';
  233. if(!bson_init_from_json(&command, cmd->s, cmd->len, &error)) {
  234. cmd->s[cmd->len] = c;
  235. LM_ERR("Failed to run command: %s\n", error.message);
  236. goto error_exec;
  237. }
  238. cmd->s[cmd->len] = c;
  239. if(emode==0) {
  240. ret = mongoc_collection_command_simple (rpl->collection, &command, NULL, &reply, &error);
  241. if (!ret) {
  242. LM_ERR("Failed to run command: %s\n", error.message);
  243. bson_destroy (&command);
  244. goto error_exec;
  245. }
  246. bson_destroy (&command);
  247. rpl->jsonrpl.s = bson_as_json (&reply, NULL);
  248. rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
  249. bson_destroy (&reply);
  250. } else {
  251. if(emode==1) {
  252. rpl->cursor = mongoc_collection_command (rpl->collection,
  253. MONGOC_QUERY_NONE,
  254. 0,
  255. 0,
  256. 0,
  257. &command,
  258. NULL,
  259. 0);
  260. } else {
  261. nres = 0;
  262. if(emode==3) nres = 1; /* return one result */
  263. rpl->cursor = mongoc_collection_find (rpl->collection,
  264. MONGOC_QUERY_NONE,
  265. 0,
  266. nres,
  267. 0,
  268. &command,
  269. NULL,
  270. NULL);
  271. }
  272. bson_destroy (&command);
  273. if(rpl->cursor==NULL) {
  274. LM_ERR("Failed to get cursor: %s\n", error.message);
  275. goto error_exec;
  276. }
  277. if (!mongoc_cursor_next (rpl->cursor, &cdoc)) {
  278. if (mongoc_cursor_error (rpl->cursor, &error)) {
  279. LM_ERR("Cursor failure: %s\n", error.message);
  280. }
  281. goto error_exec;
  282. }
  283. rpl->jsonrpl.s = bson_as_json (cdoc, NULL);
  284. rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
  285. }
  286. LM_DBG("command result: [[%s]]\n", (rpl->jsonrpl.s)?rpl->jsonrpl.s:"<null>");
  287. return 0;
  288. error_exec:
  289. return -1;
  290. }
  291. /**
  292. *
  293. */
  294. int mongodbc_exec_simple(str *srv, str *dname, str *cname, str *cmd, str *res)
  295. {
  296. return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 0);
  297. }
  298. /**
  299. *
  300. */
  301. int mongodbc_exec(str *srv, str *dname, str *cname, str *cmd, str *res)
  302. {
  303. return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 1);
  304. }
  305. /**
  306. *
  307. */
  308. int mongodbc_find(str *srv, str *dname, str *cname, str *cmd, str *res)
  309. {
  310. return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 2);
  311. }
  312. /**
  313. *
  314. */
  315. int mongodbc_find_one(str *srv, str *dname, str *cname, str *cmd, str *res)
  316. {
  317. return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 3);
  318. }
  319. /**
  320. *
  321. */
  322. mongodbc_reply_t *mongodbc_get_reply(str *name)
  323. {
  324. mongodbc_reply_t *rpl;
  325. unsigned int hid;
  326. hid = get_hash1_raw(name->s, name->len);
  327. for(rpl=_mongodbc_rpl_list; rpl; rpl=rpl->next) {
  328. if(rpl->hname==hid && rpl->rname.len==name->len
  329. && strncmp(rpl->rname.s, name->s, name->len)==0)
  330. return rpl;
  331. }
  332. /* not found - add a new one */
  333. rpl = (mongodbc_reply_t*)pkg_malloc(sizeof(mongodbc_reply_t));
  334. if(rpl==NULL)
  335. {
  336. LM_ERR("no more pkg\n");
  337. return NULL;
  338. }
  339. memset(rpl, 0, sizeof(mongodbc_reply_t));
  340. rpl->hname = hid;
  341. rpl->rname.s = (char*)pkg_malloc(name->len+1);
  342. if(rpl->rname.s==NULL)
  343. {
  344. LM_ERR("no more pkg.\n");
  345. pkg_free(rpl);
  346. return NULL;
  347. }
  348. strncpy(rpl->rname.s, name->s, name->len);
  349. rpl->rname.len = name->len;
  350. rpl->rname.s[name->len] = '\0';
  351. rpl->next = _mongodbc_rpl_list;
  352. _mongodbc_rpl_list = rpl;
  353. return rpl;
  354. }
  355. /**
  356. *
  357. */
  358. void mongodbc_destroy_reply(mongodbc_reply_t *rpl)
  359. {
  360. if(rpl->jsonrpl.s!=NULL) {
  361. bson_free(rpl->jsonrpl.s);
  362. rpl->jsonrpl.s = NULL;
  363. rpl->jsonrpl.len = 0;
  364. }
  365. if(rpl->cursor) {
  366. mongoc_cursor_destroy (rpl->cursor);
  367. rpl->cursor = NULL;
  368. }
  369. if(rpl->collection) {
  370. mongoc_collection_destroy (rpl->collection);
  371. rpl->collection = NULL;
  372. }
  373. }
  374. /**
  375. *
  376. */
  377. int mongodbc_free_reply(str *name)
  378. {
  379. mongodbc_reply_t *rpl;
  380. unsigned int hid;
  381. if(name==NULL || name->len==0) {
  382. LM_ERR("invalid parameters");
  383. return -1;
  384. }
  385. hid = get_hash1_raw(name->s, name->len);
  386. rpl = _mongodbc_rpl_list;
  387. while(rpl) {
  388. if(rpl->hname==hid && rpl->rname.len==name->len
  389. && strncmp(rpl->rname.s, name->s, name->len)==0) {
  390. mongodbc_destroy_reply(rpl);
  391. return 0;
  392. }
  393. rpl = rpl->next;
  394. }
  395. /* reply entry not found. */
  396. return -1;
  397. }
  398. /**
  399. *
  400. */
  401. int mongodbc_next_reply(str *name)
  402. {
  403. mongodbc_reply_t *rpl;
  404. unsigned int hid;
  405. bson_error_t error;
  406. const bson_t *cdoc;
  407. if(name==NULL || name->len==0) {
  408. LM_ERR("invalid parameters");
  409. return -1;
  410. }
  411. hid = get_hash1_raw(name->s, name->len);
  412. rpl = _mongodbc_rpl_list;
  413. while(rpl) {
  414. if(rpl->hname==hid && rpl->rname.len==name->len
  415. && strncmp(rpl->rname.s, name->s, name->len)==0) {
  416. break;
  417. }
  418. rpl = rpl->next;
  419. }
  420. if(!rpl) {
  421. /* reply entry not found. */
  422. return -1;
  423. }
  424. if(rpl->cursor==NULL) {
  425. LM_DBG("No active cursor for: %.*s\n", rpl->rname.len, rpl->rname.s);
  426. return -2;
  427. }
  428. if (!mongoc_cursor_next (rpl->cursor, &cdoc)) {
  429. if (mongoc_cursor_error (rpl->cursor, &error)) {
  430. LM_ERR("Cursor failure: %s\n", error.message);
  431. }
  432. return -2;
  433. }
  434. if(rpl->jsonrpl.s) {
  435. bson_free(rpl->jsonrpl.s);
  436. rpl->jsonrpl.s = NULL;
  437. rpl->jsonrpl.len = 0;
  438. }
  439. rpl->jsonrpl.s = bson_as_json (cdoc, NULL);
  440. rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
  441. LM_DBG("next cursor result: [[%s]]\n", (rpl->jsonrpl.s)?rpl->jsonrpl.s:"<null>");
  442. return 0;
  443. }
  444. /**
  445. *
  446. */
  447. int bind_ndb_mongodb(ndb_mongodb_api_t* api)
  448. {
  449. if (!api) {
  450. ERR("Invalid parameter value\n");
  451. return -1;
  452. }
  453. memset(api, 0, sizeof(ndb_mongodb_api_t));
  454. api->cmd = mongodbc_exec;
  455. api->cmd_simple = mongodbc_exec_simple;
  456. api->find = mongodbc_find;
  457. api->find_one = mongodbc_find_one;
  458. api->next_reply = mongodbc_next_reply;
  459. api->free_reply = mongodbc_free_reply;
  460. return 0;
  461. }