connection.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * $Id$
  3. *
  4. * UNIXODBC module
  5. *
  6. * Copyright (C) 2005-2006 Marco Lorrai
  7. * Copyright (C) 2008 1&1 Internet AG
  8. *
  9. * This file is part of Kamailio, a free SIP server.
  10. *
  11. * Kamailio is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * Kamailio is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. *
  25. *
  26. * History:
  27. * --------
  28. * 2005-12-01 initial commit (chgen)
  29. * 2006-01-10 UID (username) and PWD (password) attributes added to
  30. * connection string (bogdan)
  31. * 2006-05-05 extract_error passes back last error state on return (sgupta)
  32. */
  33. #include "connection.h"
  34. #include "../../mem/mem.h"
  35. #include "../../dprint.h"
  36. #include "../../ut.h"
  37. #include <time.h>
  38. #define DSN_ATTR "DSN="
  39. #define DSN_ATTR_LEN (sizeof(DSN_ATTR)-1)
  40. #define UID_ATTR "UID="
  41. #define UID_ATTR_LEN (sizeof(UID_ATTR)-1)
  42. #define PWD_ATTR "PWD="
  43. #define PWD_ATTR_LEN (sizeof(PWD_ATTR)-1)
  44. char *db_unixodbc_build_conn_str(const struct db_id* id, char *buf)
  45. {
  46. int len, ld, lu, lp;
  47. char *p;
  48. if (!buf) return 0;
  49. ld = id->database?strlen(id->database):0;
  50. lu = id->username?strlen(id->username):0;
  51. lp = id->password?strlen(id->password):0;
  52. len = (ld?(DSN_ATTR_LEN + ld + 1):0)
  53. + (lu?(UID_ATTR_LEN + lu + 1):0)
  54. + PWD_ATTR_LEN + lp + 1;
  55. if ( len>=MAX_CONN_STR_LEN ){
  56. LM_ERR("connection string too long! Increase MAX_CONN_STR_LEN"
  57. " and recompile\n");
  58. return 0;
  59. }
  60. p = buf;
  61. if (ld) {
  62. memcpy( p , DSN_ATTR, DSN_ATTR_LEN);
  63. p += DSN_ATTR_LEN;
  64. memcpy( p, id->database, ld);
  65. p += ld;
  66. }
  67. if (lu) {
  68. *(p++) = ';';
  69. memcpy( p , UID_ATTR, UID_ATTR_LEN);
  70. p += UID_ATTR_LEN;
  71. memcpy( p, id->username, lu);
  72. p += lu;
  73. }
  74. if (lp) {
  75. *(p++) = ';';
  76. memcpy( p , PWD_ATTR, PWD_ATTR_LEN);
  77. p += PWD_ATTR_LEN;
  78. memcpy( p, id->password, lp);
  79. p += lp;
  80. }
  81. *(p++) = ';';
  82. *p = 0 ; /* make it null terminated */
  83. return buf;
  84. }
  85. /*
  86. * Create a new connection structure,
  87. * open the UNIXODBC connection and set reference count to 1
  88. */
  89. struct my_con* db_unixodbc_new_connection(struct db_id* id)
  90. {
  91. SQLCHAR outstr[1024];
  92. SQLSMALLINT outstrlen;
  93. int ret;
  94. struct my_con* ptr;
  95. char conn_str[MAX_CONN_STR_LEN];
  96. if (!id)
  97. {
  98. LM_ERR("invalid parameter value\n");
  99. return 0;
  100. }
  101. ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
  102. if (!ptr)
  103. {
  104. LM_ERR("no more memory left\n");
  105. return 0;
  106. }
  107. memset(ptr, 0, sizeof(struct my_con));
  108. ptr->ref = 1;
  109. // allocate environment handle
  110. ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(ptr->env));
  111. if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
  112. {
  113. LM_ERR("could not alloc a SQL handle\n");
  114. if (ptr) pkg_free(ptr);
  115. return 0;
  116. }
  117. // set the environment
  118. ret = SQLSetEnvAttr(ptr->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
  119. if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
  120. {
  121. LM_ERR("could not set the environment\n");
  122. goto err1;
  123. }
  124. // allocate connection handle
  125. ret = SQLAllocHandle(SQL_HANDLE_DBC, ptr->env, &(ptr->dbc));
  126. if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
  127. {
  128. LM_ERR("could not alloc a connection handle %d\n", ret);
  129. goto err1;
  130. }
  131. if (!db_unixodbc_build_conn_str(id, conn_str)) {
  132. LM_ERR("failed to build connection string\n");
  133. goto err2;
  134. }
  135. LM_DBG("opening connection: unixodbc://xxxx:xxxx@%s/%s\n", ZSW(id->host),
  136. ZSW(id->database));
  137. ret = SQLDriverConnect(ptr->dbc, NULL, (SQLCHAR*)conn_str, SQL_NTS,
  138. outstr, sizeof(outstr), &outstrlen,
  139. SQL_DRIVER_COMPLETE);
  140. if (SQL_SUCCEEDED(ret))
  141. {
  142. LM_DBG("connection succeeded with reply <%s>\n", outstr);
  143. if (ret == SQL_SUCCESS_WITH_INFO)
  144. {
  145. LM_DBG("driver reported the following diagnostics\n");
  146. db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
  147. }
  148. }
  149. else
  150. {
  151. LM_ERR("failed to connect\n");
  152. db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
  153. goto err2;
  154. }
  155. ptr->stmt_handle = NULL;
  156. ptr->timestamp = time(0);
  157. ptr->id = id;
  158. return ptr;
  159. err1:
  160. SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
  161. if (ptr) pkg_free(ptr);
  162. return 0;
  163. err2:
  164. SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
  165. SQLFreeHandle(SQL_HANDLE_DBC, &(ptr->dbc));
  166. if (ptr) pkg_free(ptr);
  167. return 0;
  168. }
  169. /*
  170. * Close the connection and release memory
  171. */
  172. void db_unixodbc_free_connection(struct my_con* con)
  173. {
  174. if (!con) return;
  175. SQLFreeHandle(SQL_HANDLE_ENV, con->env);
  176. SQLDisconnect(con->dbc);
  177. SQLFreeHandle(SQL_HANDLE_DBC, con->dbc);
  178. pkg_free(con);
  179. }
  180. void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQLSMALLINT type, char* stret)
  181. {
  182. SQLINTEGER i = 0;
  183. SQLINTEGER native;
  184. SQLCHAR state[ 7 ];
  185. SQLCHAR text[256];
  186. SQLSMALLINT len;
  187. SQLRETURN ret;
  188. do
  189. {
  190. ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
  191. sizeof(text), &len );
  192. if (SQL_SUCCEEDED(ret)) {
  193. LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i,
  194. (long)native, text);
  195. if(stret) strcpy( stret, (char*)state );
  196. }
  197. }
  198. while( ret == SQL_SUCCESS );
  199. }