db_ctx.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG FOKUS
  5. * Copyright (C) 2006-2007 iptelorg GmbH
  6. *
  7. * This file is part of ser, a free SIP server.
  8. *
  9. * ser is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version
  13. *
  14. * For a license to use the ser software under conditions
  15. * other than those described here, or to purchase support for this
  16. * software, please contact iptel.org by e-mail at the following addresses:
  17. * [email protected]
  18. *
  19. * ser is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  27. */
  28. /** \ingroup DB_API
  29. * @{
  30. */
  31. #include "db_ctx.h"
  32. #include "db.h"
  33. #include "../../dprint.h"
  34. #include "../../mem/mem.h"
  35. #include <string.h>
  36. static struct db_ctx_data* db_ctx_data(str* module, db_drv_t* data)
  37. {
  38. struct db_ctx_data* newp;
  39. newp = (struct db_ctx_data*)pkg_malloc(sizeof(struct db_ctx_data));
  40. if (newp == NULL) goto error;
  41. memset(newp, '\0', sizeof(struct db_ctx_data));
  42. newp->module.s = pkg_malloc(module->len);
  43. if (newp->module.s == NULL) goto error;
  44. memcpy(newp->module.s, module->s, module->len);
  45. newp->module.len = module->len;
  46. newp->data = data;
  47. return newp;
  48. error:
  49. ERR("No memory left\n");
  50. if (newp) pkg_free(newp);
  51. return NULL;
  52. }
  53. static void db_ctx_data_free(struct db_ctx_data* ptr)
  54. {
  55. if (ptr->module.s) pkg_free(ptr->module.s);
  56. pkg_free(ptr);
  57. }
  58. /*
  59. * Create a new database context
  60. */
  61. db_ctx_t* db_ctx(const char* id)
  62. {
  63. db_ctx_t* newp;
  64. newp = (db_ctx_t*)pkg_malloc(sizeof(db_ctx_t));
  65. if (newp == NULL) goto error;
  66. memset(newp, '\0', sizeof(db_ctx_t));
  67. if (db_gen_init(&newp->gen) < 0) goto error;
  68. newp->id.len = strlen(id);
  69. newp->id.s = pkg_malloc(newp->id.len + 1);
  70. if (newp->id.s == NULL) goto error;
  71. memcpy(newp->id.s, id, newp->id.len + 1);
  72. /* Insert the newly created context into the linked list
  73. * of all existing contexts
  74. */
  75. DBLIST_INSERT_HEAD(&db_root, newp);
  76. return newp;
  77. error:
  78. if (newp) {
  79. db_gen_free(&newp->gen);
  80. if (newp->id.s) pkg_free(newp->id.s);
  81. pkg_free(newp);
  82. }
  83. return NULL;
  84. }
  85. /* Remove the database context structure
  86. * from the linked list and free all memory
  87. * used by the structure
  88. */
  89. void db_ctx_free(db_ctx_t* ctx)
  90. {
  91. int i;
  92. struct db_ctx_data* ptr, *ptr2;
  93. if (ctx == NULL) return;
  94. /* Remove the context from the linked list of
  95. * all contexts
  96. */
  97. DBLIST_REMOVE(&db_root, ctx);
  98. /* Disconnect all connections */
  99. db_disconnect(ctx);
  100. for(i = 0; i < ctx->con_n; i++) {
  101. db_con_free(ctx->con[i]);
  102. }
  103. /* Dispose all driver specific data structures as well as
  104. * the data structures in db_ctx_data linked list
  105. */
  106. SLIST_FOREACH_SAFE(ptr, &ctx->data, next, ptr2) {
  107. if (ptr->data) ptr->data->free((void*)ptr, ptr->data);
  108. db_ctx_data_free(ptr);
  109. }
  110. /* Clear all pointers to attached data structures because we have
  111. * freed the attached data structures above already. This is to
  112. * ensure that the call to db_gen_free below will not try to free
  113. * them one more time
  114. */
  115. memset(((db_gen_t*)ctx)->data, '\0', sizeof(((db_gen_t*)ctx)->data));
  116. db_gen_free(&ctx->gen);
  117. /* Destroy the structure */
  118. if (ctx->id.s) pkg_free(ctx->id.s);
  119. pkg_free(ctx);
  120. }
  121. /*
  122. * This function traverses the linked list of all db_ctx_data
  123. * structures stored in a database context to find out whether
  124. * db_ctx function of the driver whose name is in "module"
  125. * parameter has already been called.
  126. */
  127. static struct db_ctx_data* lookup_ctx_data(db_ctx_t* ctx, str* module)
  128. {
  129. struct db_ctx_data* ptr;
  130. SLIST_FOREACH(ptr, &ctx->data, next) {
  131. if (ptr->module.len == module->len &&
  132. !memcmp(ptr->module.s, module->s, module->len)) {
  133. return ptr;
  134. }
  135. }
  136. return NULL;
  137. }
  138. /*
  139. * Add a new database to database context
  140. */
  141. int db_add_db(db_ctx_t* ctx, const char* uri)
  142. {
  143. db_con_t* con;
  144. db_uri_t* parsed_uri = NULL;
  145. struct db_ctx_data* d;
  146. /* Make sure we do not attempt to open more than DB_MAX_CON
  147. * database connections within one context
  148. */
  149. if (ctx->con_n == DB_PAYLOAD_MAX) {
  150. ERR("db_add_db: Too many database connections in db context\n");
  151. return -1;
  152. }
  153. /* Get the name of desired database driver */
  154. parsed_uri = db_uri(uri);
  155. if (parsed_uri == NULL) goto error;
  156. d = lookup_ctx_data(ctx, &parsed_uri->scheme);
  157. if (d) {
  158. /* We have already called db_ctx function of this DB driver
  159. * so reuse the result from the previous run and that's it
  160. */
  161. db_payload_idx = ctx->con_n;
  162. DB_SET_PAYLOAD(ctx, d->data);
  163. } else {
  164. /* We haven't run db_ctx of the DB driver yet, so call the
  165. * function, let it create the data if needed and then remember
  166. * the result in a newly created db_ctx_data structure
  167. */
  168. /* Call db_ctx function if the driver has it */
  169. if (db_drv_call(&parsed_uri->scheme, "db_ctx", ctx, ctx->con_n) < 0) {
  170. goto error;
  171. }
  172. d = db_ctx_data(&parsed_uri->scheme, DB_GET_PAYLOAD(ctx));
  173. if (d == NULL) {
  174. /* We failed to create db_ctx_data for this payload so we have
  175. * to dispose it manually here before bailing out.
  176. */
  177. ((struct db_drv*)DB_GET_PAYLOAD(ctx))->free((void*)ctx, DB_GET_PAYLOAD(ctx));
  178. goto error;
  179. }
  180. /* Add the newly created db_ctx_data structure to the linked list so
  181. * that next time the result stored in the structure will be reused
  182. * if another database connection from the same driver is added to
  183. * the context
  184. */
  185. SLIST_INSERT_HEAD(&ctx->data, d, next);
  186. }
  187. /* We must create the db_con structure after lookup_ctx_data and associated
  188. * code above, this is to ensure that db_con in the DB driver gets called
  189. * after db_ctx in the same driver. db_con function might rely on the
  190. * previously created context structures
  191. */
  192. con = db_con(ctx, parsed_uri);
  193. if (con == NULL) goto error;
  194. ctx->con[ctx->con_n++] = con;
  195. return 0;
  196. error:
  197. if (parsed_uri) db_uri_free(parsed_uri);
  198. ERR("db: db_add_db failed\n");
  199. return -1;
  200. }
  201. /*
  202. * Attempt to connect all connections in the
  203. * context
  204. */
  205. int db_connect(db_ctx_t* ctx)
  206. {
  207. int i;
  208. for(i = 0; i < ctx->con_n; i++) {
  209. if (ctx->con[i]->connect && ctx->con[i]->connect(ctx->con[i]) < 0) return -1;
  210. }
  211. return 0;
  212. }
  213. /*
  214. * Disconnect all database connections in the
  215. * context
  216. */
  217. void db_disconnect(db_ctx_t* ctx)
  218. {
  219. int i;
  220. if (ctx != NULL) {
  221. for(i = 0; i < ctx->con_n; i++) {
  222. if (ctx->con[i]->disconnect) ctx->con[i]->disconnect(ctx->con[i]);
  223. }
  224. }
  225. }
  226. /** @} */