ora_con.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2007,2008 TRUNK MOBILE
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio 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. * Kamailio 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. #include <string.h>
  23. #include <stdio.h>
  24. #include "../../mem/mem.h"
  25. #include "../../dprint.h"
  26. #include "asynch.h"
  27. #include "ora_con.h"
  28. /*************************************************************************/
  29. /*
  30. * Create a new connection structure,
  31. * open the Oracle connection and set reference count to 1
  32. */
  33. ora_con_t* db_oracle_new_connection(const struct db_id* id)
  34. {
  35. ora_con_t* con;
  36. char buf[512];
  37. size_t uri_len;
  38. sword status;
  39. if (!id || !id->username || !*id->username || !id->password ||
  40. !*id->password || !id->database || !*id->database)
  41. {
  42. bad_param:
  43. LM_ERR("invalid parameter value\n");
  44. return NULL;
  45. }
  46. if (!id->host || !*id->host) {
  47. if (id->port) goto bad_param;
  48. uri_len = snprintf(buf, sizeof(buf), "%s", id->database);
  49. } else if (id->port) {
  50. uri_len = snprintf(buf, sizeof(buf), "%s:%u/%s",
  51. id->host, id->port, id->database);
  52. } else {
  53. uri_len = snprintf(buf, sizeof(buf), "%s/%s",
  54. id->host, id->database);
  55. }
  56. if (uri_len >= sizeof(buf)) goto bad_param;
  57. LM_DBG("opening connection: oracle://xxxx:xxxx@%s\n", buf);
  58. con = (ora_con_t*)pkg_malloc(sizeof(*con) + uri_len+1);
  59. if (!con) {
  60. LM_ERR("no private memory left\n");
  61. return NULL;
  62. }
  63. memset(con, 0, sizeof(*con));
  64. con->hdr.ref = 1;
  65. con->hdr.id = (struct db_id*)id; /* set here - freed on error */
  66. con->uri_len = uri_len;
  67. memcpy(con->uri, buf, uri_len+1);
  68. if ( OCIEnvCreate(&con->envhp,
  69. OCI_DEFAULT | OCI_NEW_LENGTH_SEMANTICS,
  70. NULL, NULL, NULL, NULL, 0, NULL) != OCI_SUCCESS
  71. || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->errhp,
  72. OCI_HTYPE_ERROR, 0, NULL) != OCI_SUCCESS
  73. || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->srvhp,
  74. OCI_HTYPE_SERVER, 0, NULL) != OCI_SUCCESS
  75. || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->svchp,
  76. OCI_HTYPE_SVCCTX, 0, NULL) != OCI_SUCCESS
  77. || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->authp,
  78. OCI_HTYPE_SESSION, 0, NULL) != OCI_SUCCESS)
  79. {
  80. LM_ERR("no oracle memory left\n");
  81. db_oracle_free_connection(con);
  82. return NULL;
  83. }
  84. status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->srvhp, 0,
  85. OCI_ATTR_SERVER, con->errhp);
  86. if (status != OCI_SUCCESS) goto connect_err;
  87. status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
  88. id->username, (ub4)strlen(id->username),
  89. OCI_ATTR_USERNAME, con->errhp);
  90. if (status != OCI_SUCCESS) goto connect_err;
  91. status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
  92. id->password, (ub4)strlen(id->password),
  93. OCI_ATTR_PASSWORD, con->errhp);
  94. if (status != OCI_SUCCESS) goto connect_err;
  95. status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->authp, 0,
  96. OCI_ATTR_SESSION, con->errhp);
  97. if (status != OCI_SUCCESS) goto connect_err;
  98. status = db_oracle_reconnect(con);
  99. if (status != OCI_SUCCESS) {
  100. connect_err:
  101. if ( (status != OCI_ERROR && status != OCI_SUCCESS_WITH_INFO)
  102. || OCIErrorGet(con->errhp, 1, NULL, &status, (OraText*)buf,
  103. sizeof(buf), OCI_HTYPE_ERROR) != OCI_SUCCESS)
  104. {
  105. LM_ERR("internal driver error\n");
  106. } else {
  107. LM_ERR("driver: %s\n", buf);
  108. }
  109. drop_connection:
  110. db_oracle_free_connection(con);
  111. return NULL;
  112. }
  113. // timelimited operation
  114. status = begin_timelimit(con, 0);
  115. if (status != OCI_SUCCESS) goto connect_err;
  116. do status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf,
  117. (ub4)sizeof(buf), OCI_HTYPE_SVCCTX);
  118. while (wait_timelimit(con, status));
  119. if (done_timelimit(con, status)) goto drop_connection;
  120. if (status != OCI_SUCCESS) goto connect_err;
  121. LM_INFO("server version is %s\n", buf);
  122. return con;
  123. }
  124. /*
  125. * Close the connection and release memory
  126. */
  127. void db_oracle_free_connection(ora_con_t* con)
  128. {
  129. if (!con) return;
  130. if (con->connected)
  131. db_oracle_disconnect(con);
  132. if (con->svchp)
  133. OCIHandleFree(con->svchp, OCI_HTYPE_SVCCTX);
  134. if (con->authp)
  135. OCIHandleFree(con->authp, OCI_HTYPE_SESSION);
  136. if (con->srvhp)
  137. OCIHandleFree(con->srvhp, OCI_HTYPE_SERVER);
  138. if (con->errhp)
  139. OCIHandleFree(con->errhp, OCI_HTYPE_ERROR);
  140. if (con->envhp)
  141. OCIHandleFree(con->envhp, OCI_HTYPE_ENV);
  142. free_db_id(con->hdr.id);
  143. pkg_free(con);
  144. }
  145. /*
  146. * Disconnect after network error
  147. */
  148. void db_oracle_disconnect(ora_con_t* con)
  149. {
  150. sword status;
  151. switch (con->connected) {
  152. default:
  153. status = OCISessionEnd(con->svchp, con->errhp, con->authp,
  154. OCI_DEFAULT);
  155. if (status != OCI_SUCCESS)
  156. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  157. case 1:
  158. status = OCIServerDetach(con->srvhp, con->errhp, OCI_DEFAULT);
  159. if (status != OCI_SUCCESS)
  160. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  161. con->connected = 0;
  162. case 0:
  163. break;
  164. }
  165. }
  166. /*
  167. * Reconnect to server (after error)
  168. */
  169. sword db_oracle_reconnect(ora_con_t* con)
  170. {
  171. sword status;
  172. if (con->connected)
  173. db_oracle_disconnect(con);
  174. /* timelimited operation, but OCI tcp-network does not support it :( */
  175. status = OCIServerAttach(con->srvhp, con->errhp, (OraText*)con->uri,
  176. con->uri_len, 0);
  177. if (status == OCI_SUCCESS) {
  178. ++con->connected;
  179. /*
  180. * timelimited operation, but OCI has BUG in asynch
  181. * implementation of OCISessionBegin :(.
  182. *
  183. * Next code is 'empiric hack' that work (tested) in v10/v11.
  184. */
  185. status = begin_timelimit(con, 1);
  186. if (status != OCI_SUCCESS) goto done;
  187. status = OCISessionBegin(con->svchp, con->errhp, con->authp,
  188. OCI_CRED_RDBMS, OCI_DEFAULT);
  189. while (wait_timelimit(con, status)) {
  190. sword code;
  191. status = OCIServerVersion(con->svchp, con->errhp, NULL,
  192. 0, OCI_HTYPE_SVCCTX);
  193. if ( status != OCI_ERROR
  194. || OCIErrorGet(con->errhp, 1, NULL, &code, NULL, 0,
  195. OCI_HTYPE_ERROR) != OCI_SUCCESS) break;
  196. switch (code) {
  197. case 24909: /* other call in progress */
  198. status = OCI_STILL_EXECUTING;
  199. continue;
  200. case 3127: /* no new operation until active ends */
  201. status = OCISessionBegin(con->svchp, con->errhp,
  202. con->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
  203. default:
  204. break;
  205. }
  206. break;
  207. }
  208. if (done_timelimit(con, status)) goto done;
  209. if (status == OCI_SUCCESS)
  210. ++con->connected;
  211. }
  212. done:
  213. return status;
  214. }