asynch.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Oracle module interface
00005  *
00006  * Copyright (C) 2007,2008 TRUNK MOBILE
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 /*
00025  * History:
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 /* Default is 3.0 second */
00043 static struct timeval request_tm = { .tv_sec = 3, .tv_usec = 0 };
00044 
00045 /* Default is 0.2 second */
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  * parse timeout value in syntax: nnn.mmm (sec/ms)
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  * set operation timeout
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  * set (re)connect timeout
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  * start timelimited operation (if work in synch mode return SUCCESS)
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 /*|| code == 3127*/))
00202    {
00203       status = OCI_STILL_EXECUTING;
00204    }
00205    return status;
00206 }
00207 
00208 
00209 /*
00210  * check completion of timelimited operation (if work in synch mode return 0)
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  * close current timelimited operation and disconnect if timeout occured
00230  * return true only if work in asynch mode and timeout detect
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 }

Generated on Thu May 17 12:00:24 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6