asynch.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * $Id$
  3. *
  4. * Oracle module interface
  5. *
  6. * Copyright (C) 2007,2008 TRUNK MOBILE
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. /*
  25. * History:
  26. * --------
  27. */
  28. #include <stdlib.h>
  29. #include <errno.h>
  30. #include <sys/time.h>
  31. #include <oci.h>
  32. #include "../../dprint.h"
  33. #include "../../sr_module.h"
  34. #include "ora_con.h"
  35. #include "asynch.h"
  36. #define MAX_TIMEOUT_S 10
  37. #define MIN_TIMEOUT_MS 100
  38. /* Default is 3.0 second */
  39. static struct timeval request_tm = { .tv_sec = 3, .tv_usec = 0 };
  40. /* Default is 0.2 second */
  41. static struct timeval restore_tm = { .tv_sec = 0, .tv_usec = 200*1000 };
  42. static const struct timeval defrest_tm = { .tv_sec = 0, .tv_usec = 200*1000 };
  43. static int synch_mode;
  44. static int cur_asynch_mode;
  45. static struct timeval wtm;
  46. static __inline__ int is_zero_tm(const struct timeval* tv)
  47. {
  48. return !tv->tv_usec && !tv->tv_sec;
  49. }
  50. /*
  51. * parse timeout value in syntax: nnn.mmm (sec/ms)
  52. */
  53. static int set_tv(unsigned type, const char* val, struct timeval* tv)
  54. {
  55. char *eptr;
  56. unsigned long s, ms;
  57. double dv;
  58. if (PARAM_TYPE_MASK(type) != PARAM_STRING) {
  59. LM_ERR("type of parameter is not PARAM_STRING\n");
  60. return -1;
  61. }
  62. if (!val || !*val) {
  63. LM_ERR("empty parameter\n");
  64. return -1;
  65. }
  66. errno = 0;
  67. dv = strtod(val, &eptr);
  68. if (*eptr) {
  69. LM_ERR("invalid parameter string\n");
  70. return -2;
  71. }
  72. if ( errno
  73. || dv > (double)MAX_TIMEOUT_S
  74. || (dv && dv < ((double)MIN_TIMEOUT_MS)/1000))
  75. {
  76. LM_ERR("value must be between 0.%u and %u.0\n",
  77. MIN_TIMEOUT_MS, MAX_TIMEOUT_S);
  78. return -3;
  79. }
  80. s = (unsigned)dv;
  81. dv -= (double)s;
  82. ms = (unsigned)(dv * 1000);
  83. tv->tv_sec = (time_t)s;
  84. tv->tv_usec = (suseconds_t)ms;
  85. return 0;
  86. }
  87. /*
  88. * set operation timeout
  89. */
  90. int set_timeout(unsigned type, const char* val)
  91. {
  92. int rc = set_tv(type, val, &request_tm);
  93. if (!rc) {
  94. synch_mode = is_zero_tm(&request_tm);
  95. if (!synch_mode && is_zero_tm(&restore_tm))
  96. restore_tm = defrest_tm;
  97. }
  98. return rc;
  99. }
  100. /*
  101. * set (re)connect timeout
  102. */
  103. int set_reconnect(unsigned type, const char* val)
  104. {
  105. int rc = set_tv(type, val, &restore_tm);
  106. if (!synch_mode && is_zero_tm(&restore_tm)) {
  107. LM_WARN("in asyncronus mode reconnect time can't be zero. "
  108. "Set default value\n");
  109. restore_tm = defrest_tm;
  110. }
  111. return rc;
  112. }
  113. static sword change_mode(ora_con_t* con)
  114. {
  115. return OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, NULL, 0,
  116. OCI_ATTR_NONBLOCKING_MODE, con->errhp);
  117. }
  118. /*
  119. * start timelimited operation (if work in synch mode return SUCCESS)
  120. */
  121. sword begin_timelimit(ora_con_t* con, int connect)
  122. {
  123. struct timeval* tv;
  124. sword status;
  125. if (synch_mode)
  126. return OCI_SUCCESS;
  127. if (connect || cur_asynch_mode) {
  128. ub1 mode;
  129. status = OCIAttrGet(con->svchp, OCI_HTYPE_SVCCTX, &mode, NULL,
  130. OCI_ATTR_NONBLOCKING_MODE, con->errhp);
  131. if (status != OCI_SUCCESS)
  132. return status;
  133. if (mode) {
  134. status = change_mode(con);
  135. if (status != OCI_SUCCESS)
  136. return status;
  137. }
  138. cur_asynch_mode = 0;
  139. }
  140. status = change_mode(con);
  141. if (status != OCI_SUCCESS && connect >= 0)
  142. return status;
  143. cur_asynch_mode = 1;
  144. gettimeofday(&wtm, NULL);
  145. tv = &request_tm;
  146. if (connect)
  147. tv = &restore_tm;
  148. wtm.tv_sec += tv->tv_sec;
  149. wtm.tv_usec += tv->tv_usec;
  150. if (wtm.tv_usec >= 1000000) {
  151. wtm.tv_usec -= 1000000;
  152. ++wtm.tv_sec;
  153. }
  154. return OCI_SUCCESS;
  155. }
  156. static sword remap_status(ora_con_t* con, sword status)
  157. {
  158. sword code;
  159. if ( status == OCI_ERROR
  160. && OCIErrorGet(con->errhp, 1, NULL, &code,
  161. NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
  162. && (code == 3123 /*|| code == 3127*/))
  163. {
  164. status = OCI_STILL_EXECUTING;
  165. }
  166. return status;
  167. }
  168. /*
  169. * check completion of timelimited operation (if work in synch mode return 0)
  170. */
  171. int wait_timelimit(ora_con_t* con, sword status)
  172. {
  173. struct timeval cur;
  174. if (!cur_asynch_mode)
  175. return 0;
  176. if (remap_status(con, status) != OCI_STILL_EXECUTING)
  177. return 0;
  178. gettimeofday(&cur, NULL);
  179. return ( cur.tv_sec < wtm.tv_sec
  180. || (cur.tv_sec == wtm.tv_sec && cur.tv_usec < wtm.tv_usec));
  181. }
  182. /*
  183. * close current timelimited operation and disconnect if timeout occured
  184. * return true only if work in asynch mode and timeout detect
  185. */
  186. int done_timelimit(ora_con_t* con, sword status)
  187. {
  188. int ret = 0;
  189. if (!cur_asynch_mode)
  190. return 0;
  191. if (remap_status(con, status) == OCI_STILL_EXECUTING) {
  192. sword code;
  193. status = OCIBreak(con->svchp, con->errhp);
  194. if (status != OCI_SUCCESS)
  195. LM_ERR("driver: %s\n",
  196. db_oracle_error(con, status));
  197. status = OCIReset(con->svchp, con->errhp);
  198. if ( status == OCI_ERROR
  199. && OCIErrorGet(con->errhp, 1, NULL, &code,
  200. NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
  201. && code == 1013)
  202. {
  203. status = OCI_SUCCESS;
  204. }
  205. if (status != OCI_SUCCESS)
  206. LM_ERR("driver: %s\n",
  207. db_oracle_error(con, status));
  208. db_oracle_disconnect(con);
  209. ++ret;
  210. } else {
  211. status = change_mode(con);
  212. if (status != OCI_SUCCESS) {
  213. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  214. ++ret;
  215. } else {
  216. cur_asynch_mode = 0;
  217. }
  218. }
  219. return ret;
  220. }