00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <stdlib.h>
00030 #include <errno.h>
00031 #include <sys/time.h>
00032 #include <oci.h>
00033 #include "../../dprint.h"
00034 #include "../../sr_module.h"
00035 #include "ora_con.h"
00036 #include "asynch.h"
00037
00038 #define MAX_TIMEOUT_S 10
00039 #define MIN_TIMEOUT_MS 100
00040
00041
00042
00043 static struct timeval request_tm = { .tv_sec = 3, .tv_usec = 0 };
00044
00045
00046 static struct timeval restore_tm = { .tv_sec = 0, .tv_usec = 200*1000 };
00047 static const struct timeval defrest_tm = { .tv_sec = 0, .tv_usec = 200*1000 };
00048
00049 static int synch_mode;
00050 static int cur_asynch_mode;
00051 static struct timeval wtm;
00052
00053
00054 static __inline__ int is_zero_tm(const struct timeval* tv)
00055 {
00056 return !tv->tv_usec && !tv->tv_sec;
00057 }
00058
00059
00060
00061
00062
00063 static int set_tv(unsigned type, const char* val, struct timeval* tv)
00064 {
00065 char *eptr;
00066 unsigned long s, ms;
00067 double dv;
00068
00069 if (type != STR_PARAM) {
00070 LM_ERR("type of parameter is no STR\n");
00071 return -1;
00072 }
00073
00074 if (!val || !*val) {
00075 LM_ERR("empty parameter\n");
00076 return -1;
00077 }
00078
00079 errno = 0;
00080 dv = strtod(val, &eptr);
00081
00082 if (*eptr) {
00083 LM_ERR("invalid parameter string\n");
00084 return -2;
00085 }
00086
00087 if ( errno
00088 || dv > (double)MAX_TIMEOUT_S
00089 || (dv && dv < ((double)MIN_TIMEOUT_MS)/1000))
00090 {
00091 LM_ERR("value must be between 0.%u and %u.0\n",
00092 MIN_TIMEOUT_MS, MAX_TIMEOUT_S);
00093 return -3;
00094 }
00095
00096 s = (unsigned)dv;
00097 dv -= (double)s;
00098 ms = (unsigned)(dv * 1000);
00099 tv->tv_sec = (time_t)s;
00100 tv->tv_usec = (suseconds_t)ms;
00101 return 0;
00102 }
00103
00104
00105
00106
00107
00108 int set_timeout(unsigned type, const char* val)
00109 {
00110 int rc = set_tv(type, val, &request_tm);
00111
00112 if (!rc) {
00113 synch_mode = is_zero_tm(&request_tm);
00114 if (!synch_mode && is_zero_tm(&restore_tm))
00115 restore_tm = defrest_tm;
00116 }
00117
00118 return rc;
00119 }
00120
00121
00122
00123
00124
00125 int set_reconnect(unsigned type, const char* val)
00126 {
00127 int rc = set_tv(type, val, &restore_tm);
00128
00129 if (!synch_mode && is_zero_tm(&restore_tm)) {
00130 LM_WARN("in asyncronus mode reconnect time can't be zero. "
00131 "Set default value\n");
00132 restore_tm = defrest_tm;
00133 }
00134
00135 return rc;
00136 }
00137
00138
00139 static sword change_mode(ora_con_t* con)
00140 {
00141 return OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, NULL, 0,
00142 OCI_ATTR_NONBLOCKING_MODE, con->errhp);
00143 }
00144
00145
00146
00147
00148
00149 sword begin_timelimit(ora_con_t* con, int connect)
00150 {
00151 struct timeval* tv;
00152 sword status;
00153
00154 if (synch_mode)
00155 return OCI_SUCCESS;
00156
00157 if (connect || cur_asynch_mode) {
00158 ub1 mode;
00159
00160 status = OCIAttrGet(con->svchp, OCI_HTYPE_SVCCTX, &mode, NULL,
00161 OCI_ATTR_NONBLOCKING_MODE, con->errhp);
00162 if (status != OCI_SUCCESS)
00163 return status;
00164
00165 if (mode) {
00166 status = change_mode(con);
00167 if (status != OCI_SUCCESS)
00168 return status;
00169 }
00170 cur_asynch_mode = 0;
00171 }
00172
00173 status = change_mode(con);
00174 if (status != OCI_SUCCESS && connect >= 0)
00175 return status;
00176
00177 cur_asynch_mode = 1;
00178
00179 gettimeofday(&wtm, NULL);
00180 tv = &request_tm;
00181 if (connect)
00182 tv = &restore_tm;
00183 wtm.tv_sec += tv->tv_sec;
00184 wtm.tv_usec += tv->tv_usec;
00185 if (wtm.tv_usec >= 1000000) {
00186 wtm.tv_usec -= 1000000;
00187 ++wtm.tv_sec;
00188 }
00189
00190 return OCI_SUCCESS;
00191 }
00192
00193
00194 static sword remap_status(ora_con_t* con, sword status)
00195 {
00196 sword code;
00197
00198 if ( status == OCI_ERROR
00199 && OCIErrorGet(con->errhp, 1, NULL, &code,
00200 NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
00201 && (code == 3123 ))
00202 {
00203 status = OCI_STILL_EXECUTING;
00204 }
00205 return status;
00206 }
00207
00208
00209
00210
00211
00212 int wait_timelimit(ora_con_t* con, sword status)
00213 {
00214 struct timeval cur;
00215
00216 if (!cur_asynch_mode)
00217 return 0;
00218
00219 if (remap_status(con, status) != OCI_STILL_EXECUTING)
00220 return 0;
00221
00222 gettimeofday(&cur, NULL);
00223 return ( cur.tv_sec < wtm.tv_sec
00224 || (cur.tv_sec == wtm.tv_sec && cur.tv_usec < wtm.tv_usec));
00225 }
00226
00227
00228
00229
00230
00231
00232 int done_timelimit(ora_con_t* con, sword status)
00233 {
00234 int ret = 0;
00235
00236 if (!cur_asynch_mode)
00237 return 0;
00238
00239 if (remap_status(con, status) == OCI_STILL_EXECUTING) {
00240 sword code;
00241
00242 status = OCIBreak(con->svchp, con->errhp);
00243 if (status != OCI_SUCCESS)
00244 LM_ERR("driver: %s\n",
00245 db_oracle_error(con, status));
00246
00247 status = OCIReset(con->svchp, con->errhp);
00248 if ( status == OCI_ERROR
00249 && OCIErrorGet(con->errhp, 1, NULL, &code,
00250 NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS
00251 && code == 1013)
00252 {
00253 status = OCI_SUCCESS;
00254 }
00255 if (status != OCI_SUCCESS)
00256 LM_ERR("driver: %s\n",
00257 db_oracle_error(con, status));
00258 db_oracle_disconnect(con);
00259 ++ret;
00260 } else {
00261 status = change_mode(con);
00262 if (status != OCI_SUCCESS) {
00263 LM_ERR("driver: %s\n", db_oracle_error(con, status));
00264 ++ret;
00265 } else {
00266 cur_asynch_mode = 0;
00267 }
00268 }
00269 return ret;
00270 }