818202b
From 80847a3200e71f3d0aefcf4505a5988b56decf9f Mon Sep 17 00:00:00 2001
818202b
From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A1=D0=B0=D0=BC?=
818202b
 =?UTF-8?q?=D1=83=D1=81=D0=B5=D0=BD=D0=BA=D0=BE?= <samusenko@msm.ru>
e73f7b5
Date: Mon, 25 Jun 2012 17:54:27 +0400
818202b
Subject: [PATCH 5/8] Removed all async Oracle operations - they didn't work
e73f7b5
 well anyway
e73f7b5
e73f7b5
---
dd6e1a3
 modules/db_oracle/asynch.c    | 270 ------------------------------------------
dd6e1a3
 modules/db_oracle/asynch.h    |  62 ----------
dd6e1a3
 modules/db_oracle/db_oracle.c |   2 +-
dd6e1a3
 modules/db_oracle/dbase.c     |  53 +++------
dd6e1a3
 modules/db_oracle/ora_con.c   |  73 ++++--------
dd6e1a3
 modules/db_oracle/ora_con.h   |   3 +-
d9c4e87
 modules/db_oracle/res.c       | 110 +++++++++--------
dd6e1a3
 modules/db_oracle/timer.c     | 131 ++++++++++++++++++++
dd6e1a3
 modules/db_oracle/timer.h     |  22 ++++
d9c4e87
 9 files changed, 256 insertions(+), 470 deletions(-)
e73f7b5
 delete mode 100644 modules/db_oracle/asynch.c
e73f7b5
 delete mode 100644 modules/db_oracle/asynch.h
e73f7b5
 create mode 100644 modules/db_oracle/timer.c
e73f7b5
 create mode 100644 modules/db_oracle/timer.h
e73f7b5
e73f7b5
diff --git a/modules/db_oracle/db_oracle.c b/modules/db_oracle/db_oracle.c
e73f7b5
index 70cfe40..40c7692 100644
e73f7b5
--- a/modules/db_oracle/db_oracle.c
e73f7b5
+++ b/modules/db_oracle/db_oracle.c
e73f7b5
@@ -31,7 +31,7 @@
e73f7b5
 #include "../../sr_module.h"
e73f7b5
 #include "../../db/db.h"
e73f7b5
 #include "dbase.h"
e73f7b5
-#include "asynch.h"
e73f7b5
+#include "timer.h"
e73f7b5
 
e73f7b5
 static int oracle_mod_init(void);
e73f7b5
 static void destroy(void);
e73f7b5
diff --git a/modules/db_oracle/dbase.c b/modules/db_oracle/dbase.c
e73f7b5
index d129e11..be2352e 100644
e73f7b5
--- a/modules/db_oracle/dbase.c
e73f7b5
+++ b/modules/db_oracle/dbase.c
e73f7b5
@@ -36,7 +36,7 @@
e73f7b5
 #include "val.h"
e73f7b5
 #include "ora_con.h"
e73f7b5
 #include "res.h"
e73f7b5
-#include "asynch.h"
e73f7b5
+#include "timer.h"
e73f7b5
 #include "dbase.h"
e73f7b5
 
e73f7b5
 
e73f7b5
@@ -212,7 +212,6 @@ static int db_oracle_submit_query(const db_con_t* _h, const str* _s)
e73f7b5
 	OCIDate odt[sizeof(bind)/sizeof(bind[0])];
e73f7b5
 	str tmps;
e73f7b5
 	sword status;
e73f7b5
-	int pass;
e73f7b5
 	ora_con_t* con = CON_ORA(_h);
e73f7b5
 	query_data_t* pqd = con->pqdata;
e73f7b5
 	size_t hc = pqd->_n + pqd->_nw;
e73f7b5
@@ -223,32 +222,16 @@ static int db_oracle_submit_query(const db_con_t* _h, const str* _s)
e73f7b5
 			(unsigned)hc);
e73f7b5
 		return -1;
e73f7b5
 	}
e73f7b5
-	
e73f7b5
-	if (!pqd->_rs) {
e73f7b5
-		/*
e73f7b5
-		 * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS
e73f7b5
-		 * in StmtExecute
e73f7b5
-		 */
e73f7b5
-		tmps.len = snprintf(st_buf, sizeof(st_buf),
e73f7b5
-			"begin %.*s; commit write batch nowait; end;",
e73f7b5
-			_s->len, _s->s);
e73f7b5
-		if ((unsigned)tmps.len >= sizeof(st_buf))
e73f7b5
-			return sql_buf_small();
e73f7b5
-		tmps.s = st_buf;
e73f7b5
-		_s = &tmps;
e73f7b5
-	}
e73f7b5
 
e73f7b5
-	pass = 1;
e73f7b5
-	if (!con->connected) {
e73f7b5
+	if (con->connected != 2) {
e73f7b5
 		status = db_oracle_reconnect(con);
e73f7b5
 		if (status != OCI_SUCCESS) {
e73f7b5
 			LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status));
e73f7b5
 			return -2;
e73f7b5
 		}
e73f7b5
 		LM_INFO("connection restored\n");
e73f7b5
-		--pass;
e73f7b5
 	}
e73f7b5
-repeat:
e73f7b5
+
e73f7b5
 	stmthp = NULL;
e73f7b5
 	status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp,
e73f7b5
 		    OCI_HTYPE_STMT, 0, NULL);
e73f7b5
@@ -291,14 +274,10 @@ bind_err:
e73f7b5
 		}
e73f7b5
 	}
e73f7b5
 
e73f7b5
-	// timelimited operation
e73f7b5
-	status = begin_timelimit(con, 0);
e73f7b5
-	if (status != OCI_SUCCESS) goto ora_err;
e73f7b5
-	do status = OCIStmtExecute(con->svchp, stmthp, con->errhp,
e73f7b5
-		!pqd->_rs, 0, NULL, NULL,
e73f7b5
-		pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT);
e73f7b5
-	while (wait_timelimit(con, status));
e73f7b5
-	if (done_timelimit(con, status)) goto stop_exec;
e73f7b5
+	request_timer();
e73f7b5
+	status = OCIStmtExecute(con->svchp, stmthp, con->errhp,
e73f7b5
+		!pqd->_rs, 0, NULL, NULL, pqd->_rs ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS);
e73f7b5
+	timer_stop();
e73f7b5
 	switch (status)	{
e73f7b5
 	case OCI_SUCCESS_WITH_INFO:
e73f7b5
 		LM_WARN("driver: %s\n", db_oracle_errorinfo(con));
e73f7b5
@@ -310,8 +289,8 @@ bind_err:
e73f7b5
 			OCIHandleFree(stmthp, OCI_HTYPE_STMT);
e73f7b5
 		return 0;
e73f7b5
 	default:
e73f7b5
-	    pass = -pass;
e73f7b5
-	    break;
e73f7b5
+		LM_ERR("timeout/not connected to oracle\n");
e73f7b5
+		break;
e73f7b5
 	}
e73f7b5
 
e73f7b5
 ora_err:
e73f7b5
@@ -319,15 +298,13 @@ ora_err:
e73f7b5
 stop_exec:
e73f7b5
 	if (stmthp)
e73f7b5
 		OCIHandleFree(stmthp, OCI_HTYPE_STMT);
e73f7b5
-	if (pass == -1 && !con->connected) {
e73f7b5
-		/* Attemtp to reconnect */
e73f7b5
-		if (db_oracle_reconnect(con) == OCI_SUCCESS) {
e73f7b5
-			LM_NOTICE("attempt repeat after reconnect\n");
e73f7b5
-			pass = 0;
e73f7b5
-			goto repeat;
e73f7b5
-		}
e73f7b5
+	LM_INFO("reconnecting to oracle...\n");
e73f7b5
+	/* Attempt to reconnect */
e73f7b5
+	if (db_oracle_reconnect(con) == OCI_SUCCESS)
e73f7b5
+		LM_INFO("connection restored\n");
e73f7b5
+	else
e73f7b5
 		LM_ERR("connection loss\n");
e73f7b5
-	}
e73f7b5
+
e73f7b5
 	return -4;
e73f7b5
 }
e73f7b5
 
e73f7b5
diff --git a/modules/db_oracle/ora_con.c b/modules/db_oracle/ora_con.c
e73f7b5
index 73ced27..f03f753 100644
e73f7b5
--- a/modules/db_oracle/ora_con.c
e73f7b5
+++ b/modules/db_oracle/ora_con.c
e73f7b5
@@ -22,9 +22,10 @@
e73f7b5
 
e73f7b5
 #include <string.h>
e73f7b5
 #include <stdio.h>
e73f7b5
+#include <errno.h>
e73f7b5
 #include "../../mem/mem.h"
e73f7b5
 #include "../../dprint.h"
e73f7b5
-#include "asynch.h"
e73f7b5
+#include "timer.h"
e73f7b5
 #include "ora_con.h"
e73f7b5
 
e73f7b5
 /*************************************************************************/
e73f7b5
@@ -105,6 +106,12 @@ bad_param:
e73f7b5
 	status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->authp, 0,
e73f7b5
                    OCI_ATTR_SESSION, con->errhp);
e73f7b5
 	if (status != OCI_SUCCESS) goto connect_err;
e73f7b5
+
e73f7b5
+        if (init_ora_timer(con) != 0) {
e73f7b5
+           LM_ERR("can't start oracle timer thread\n");
e73f7b5
+           goto drop_connection;
e73f7b5
+        }
e73f7b5
+
e73f7b5
 	status = db_oracle_reconnect(con);
e73f7b5
 	if (status != OCI_SUCCESS) {
e73f7b5
 connect_err:
e73f7b5
@@ -122,12 +129,11 @@ drop_connection:
e73f7b5
 	}
e73f7b5
 
e73f7b5
 	// timelimited operation
e73f7b5
-	status = begin_timelimit(con, 0);
e73f7b5
-	if (status != OCI_SUCCESS) goto connect_err;
e73f7b5
-	do status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf,
e73f7b5
+	request_timer();
e73f7b5
+	status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf,
e73f7b5
 		(ub4)sizeof(buf), OCI_HTYPE_SVCCTX);
e73f7b5
-	while (wait_timelimit(con, status));
e73f7b5
-	if (done_timelimit(con, status)) goto drop_connection;
e73f7b5
+	timer_stop();
e73f7b5
+	
e73f7b5
 	if (status != OCI_SUCCESS) goto connect_err;
e73f7b5
 	LM_INFO("server version is %s\n", buf);
e73f7b5
 	return con;
e73f7b5
@@ -139,6 +145,7 @@ drop_connection:
e73f7b5
  */
e73f7b5
 void db_oracle_free_connection(ora_con_t* con)
e73f7b5
 {
e73f7b5
+	destroy_ora_timer(con);
e73f7b5
 	if (!con) return;
e73f7b5
 
e73f7b5
 	if (con->connected)
e73f7b5
@@ -164,20 +171,17 @@ void db_oracle_free_connection(ora_con_t* con)
e73f7b5
 void db_oracle_disconnect(ora_con_t* con)
e73f7b5
 {
e73f7b5
 	sword status;
e73f7b5
-
e73f7b5
-	switch (con->connected) {
e73f7b5
-	default:
e73f7b5
-		status = OCISessionEnd(con->svchp, con->errhp, con->authp,
e73f7b5
-			OCI_DEFAULT);
e73f7b5
-		if (status != OCI_SUCCESS)
e73f7b5
-			LM_ERR("driver: %s\n", db_oracle_error(con, status));
e73f7b5
-	case 1:
e73f7b5
+	if (con->connected > 0) {
e73f7b5
+		if (con->connected > 1) {
e73f7b5
+			status = OCISessionEnd(con->svchp, con->errhp, con->authp,
e73f7b5
+				OCI_DEFAULT);
e73f7b5
+			if (status != OCI_SUCCESS)
e73f7b5
+				LM_ERR("driver: %s\n", db_oracle_error(con, status));
e73f7b5
+		}
e73f7b5
 		status = OCIServerDetach(con->srvhp, con->errhp, OCI_DEFAULT);
e73f7b5
 		if (status != OCI_SUCCESS)
e73f7b5
 			LM_ERR("driver: %s\n", db_oracle_error(con, status));
e73f7b5
 		con->connected = 0;
e73f7b5
-	case 0:
e73f7b5
-		break;
e73f7b5
 	}
e73f7b5
 }
e73f7b5
 
e73f7b5
@@ -192,48 +196,19 @@ sword db_oracle_reconnect(ora_con_t* con)
e73f7b5
 	if (con->connected)
e73f7b5
 		db_oracle_disconnect(con);
e73f7b5
 
e73f7b5
-	/* timelimited operation, but OCI tcp-network does not support it :( */
e73f7b5
+	restore_timer();
e73f7b5
 	status = OCIServerAttach(con->srvhp, con->errhp, (OraText*)con->uri,
e73f7b5
 		con->uri_len, 0);
e73f7b5
+	timer_stop();
e73f7b5
 	if (status == OCI_SUCCESS) {
e73f7b5
 		++con->connected;
e73f7b5
-		/*
e73f7b5
-		 * timelimited operation, but OCI has BUG in asynch
e73f7b5
-		 * implementation of OCISessionBegin :(.
e73f7b5
-		 *
e73f7b5
-		 * Next code is 'empiric hack' that work (tested) in v10/v11.
e73f7b5
-		 */
e73f7b5
-		status = begin_timelimit(con, 1);
e73f7b5
-		if (status != OCI_SUCCESS) goto done;
e73f7b5
+		request_timer();
e73f7b5
 		status = OCISessionBegin(con->svchp, con->errhp, con->authp,
e73f7b5
 			OCI_CRED_RDBMS, OCI_DEFAULT);
e73f7b5
-		while (wait_timelimit(con, status)) {
e73f7b5
-			sword code;
e73f7b5
-
e73f7b5
-			status = OCIServerVersion(con->svchp, con->errhp, NULL,
e73f7b5
-				0, OCI_HTYPE_SVCCTX);
e73f7b5
-
e73f7b5
-			if (   status != OCI_ERROR
e73f7b5
-			    || OCIErrorGet(con->errhp, 1, NULL, &code, NULL, 0,
e73f7b5
-				     OCI_HTYPE_ERROR) != OCI_SUCCESS) break;
e73f7b5
-			switch (code) {
e73f7b5
-			case 24909:	/* other call in progress */
e73f7b5
-				status = OCI_STILL_EXECUTING;
e73f7b5
-				continue;
e73f7b5
-
e73f7b5
-			case 3127:	/* no new operation until active ends */
e73f7b5
-				status = OCISessionBegin(con->svchp, con->errhp,
e73f7b5
-					con->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
e73f7b5
-			default:
e73f7b5
-				break;
e73f7b5
-			}
e73f7b5
-			break;
e73f7b5
-		}
e73f7b5
-		if (done_timelimit(con, status)) goto done;
e73f7b5
+		timer_stop();
e73f7b5
 
e73f7b5
 		if (status == OCI_SUCCESS)
e73f7b5
 			++con->connected;
e73f7b5
 	}
e73f7b5
-done:
e73f7b5
 	return status;
e73f7b5
 }
e73f7b5
diff --git a/modules/db_oracle/ora_con.h b/modules/db_oracle/ora_con.h
e73f7b5
index 5835ffe..7267bee 100644
e73f7b5
--- a/modules/db_oracle/ora_con.h
e73f7b5
+++ b/modules/db_oracle/ora_con.h
e73f7b5
@@ -50,7 +50,8 @@ struct ora_con {
e73f7b5
 
e73f7b5
 	int connected;		/* Authorized session started */
e73f7b5
 	int bindpos;		/* Last Bind handle position */
e73f7b5
-	
e73f7b5
+	pthread_t timer;
e73f7b5
+
e73f7b5
 	query_data_t* pqdata;	/* Temporary: cb data for submit_query/store_result */
e73f7b5
 
e73f7b5
 	int  uri_len;
e73f7b5
diff --git a/modules/db_oracle/res.c b/modules/db_oracle/res.c
d9c4e87
index e9e6233..2c625f8 100644
e73f7b5
--- a/modules/db_oracle/res.c
e73f7b5
+++ b/modules/db_oracle/res.c
e73f7b5
@@ -32,7 +32,7 @@
e73f7b5
 #include "../../dprint.h"
e73f7b5
 #include "ora_con.h"
e73f7b5
 #include "dbase.h"
e73f7b5
-#include "asynch.h"
e73f7b5
+#include "timer.h"
e73f7b5
 #include "res.h"
e73f7b5
 
e73f7b5
 
e73f7b5
@@ -54,6 +54,10 @@ struct dmap {
e73f7b5
 };
e73f7b5
 typedef struct dmap dmap_t;
e73f7b5
 
e73f7b5
+typedef struct ora_row {
e73f7b5
+   struct db_row hdr;
e73f7b5
+   struct ora_row* next;
e73f7b5
+} ora_row_t;
e73f7b5
 
e73f7b5
 /*
e73f7b5
  * Get and convert columns from a result. Define handlers and buffers
e73f7b5
@@ -362,66 +366,74 @@ static int convert_row(db_res_t* _res, db_row_t* _r, dmap_t* _d)
e73f7b5
  */
e73f7b5
 static int get_rows(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d)
e73f7b5
 {
e73f7b5
-	ub4 rcnt;
e73f7b5
+	ub4 i = 0, rcnt = 0;
e73f7b5
 	sword status;
e73f7b5
 	unsigned n = RES_COL_N(_r);
e73f7b5
-
e73f7b5
+	// Since OCI have not "mysql_num_rows()", sequentialy fetch all rows into tmp area orow_list.
e73f7b5
+	// Then call db_allocate_rows() and copy tmp to db module.
e73f7b5
+	ora_row_t *orow_list = NULL, *orow_it, *orow_tail;
e73f7b5
+	
e73f7b5
 	memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
e73f7b5
-
e73f7b5
-	// timelimited operation
e73f7b5
-	status = begin_timelimit(con, 0);
e73f7b5
-	if (status != OCI_SUCCESS) goto ora_err;
e73f7b5
-	do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_NEXT, 0,
e73f7b5
-		OCI_DEFAULT);
e73f7b5
-	while (wait_timelimit(con, status));
e73f7b5
-	if (done_timelimit(con, status)) goto stop_load;
e73f7b5
-	if (status != OCI_SUCCESS) {
e73f7b5
-		if (status != OCI_NO_DATA)
e73f7b5
-			goto ora_err;
e73f7b5
-
e73f7b5
-		RES_ROW_N(_r) = 0;
e73f7b5
-		RES_ROWS(_r) = NULL;
e73f7b5
-		return 0;
e73f7b5
-	}
e73f7b5
-
e73f7b5
-	status = OCIAttrGet(_c, OCI_HTYPE_STMT, &rcnt, NULL,
e73f7b5
-		OCI_ATTR_CURRENT_POSITION, con->errhp);
e73f7b5
-	if (status != OCI_SUCCESS) goto ora_err;
e73f7b5
-	if (!rcnt) {
e73f7b5
-		LM_ERR("lastpos==0\n");
e73f7b5
-		goto stop_load;
e73f7b5
+	
e73f7b5
+	request_timer();
e73f7b5
+	while ((status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_NEXT, 0,
e73f7b5
+		OCI_DEFAULT)) == OCI_SUCCESS) {
e73f7b5
+		timer_stop();
e73f7b5
+	
e73f7b5
+		orow_it = (ora_row_t*) pkg_malloc(sizeof(ora_row_t) + sizeof(db_val_t)*RES_COL_N(_r));
e73f7b5
+		if (orow_it == NULL) {
e73f7b5
+			LM_ERR("no private memory left\n");
e73f7b5
+			goto stop_load;
e73f7b5
+		}
e73f7b5
+		memset(orow_it, 0, sizeof(ora_row_t) + sizeof(db_val_t)*RES_COL_N(_r));
e73f7b5
+		orow_it->hdr.values = (db_val_t*)(orow_it+1);
e73f7b5
+		
e73f7b5
+		if (orow_list == NULL)
e73f7b5
+			orow_list = orow_it;
e73f7b5
+		else
e73f7b5
+			orow_tail->next = orow_it;
e73f7b5
+		orow_tail = orow_it;
e73f7b5
+		
e73f7b5
+		if (convert_row(_r, &orow_it->hdr, _d) < 0) {
e73f7b5
+			LM_ERR("erroc convert row\n");
e73f7b5
+			goto stop_load;
e73f7b5
+		}
e73f7b5
+		memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
e73f7b5
+		++rcnt;
e73f7b5
+		request_timer();
e73f7b5
 	}
e73f7b5
-
e73f7b5
+	timer_stop();
e73f7b5
+	if (status != OCI_NO_DATA)
e73f7b5
+		goto ora_err;
e73f7b5
+	
e73f7b5
 	RES_ROW_N(_r) = rcnt;
e73f7b5
 	if (db_allocate_rows( _r, rcnt)!=0) {
e73f7b5
 		LM_ERR("no private memory left\n");
e73f7b5
-		return -1;
e73f7b5
+		goto stop_load;
e73f7b5
 	}
e73f7b5
-
e73f7b5
-	while ( 1 ) {
e73f7b5
-		if (convert_row(_r, &RES_ROWS(_r)[--rcnt], _d) < 0) {
e73f7b5
-			LM_ERR("error convert row\n");
e73f7b5
-			goto stop_load;
e73f7b5
-		}
e73f7b5
-
e73f7b5
-		if (!rcnt)
e73f7b5
-			return 0;
e73f7b5
-
e73f7b5
-		memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
e73f7b5
-		// timelimited operation
e73f7b5
-		status = begin_timelimit(con, 0);
e73f7b5
-		if (status != OCI_SUCCESS) goto ora_err;
e73f7b5
-		do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_PRIOR, 0,
e73f7b5
-			OCI_DEFAULT);
e73f7b5
-		while (wait_timelimit(con, status));
e73f7b5
-		if (done_timelimit(con, status)) goto stop_load;
e73f7b5
-		if (status != OCI_SUCCESS) break;
e73f7b5
+	
e73f7b5
+	for (orow_it = orow_list; orow_it; orow_it = orow_it->next) {
e73f7b5
+		memcpy(ROW_VALUES(&RES_ROWS(_r)[i]), ROW_VALUES(&orow_it->hdr), sizeof(db_val_t)*RES_COL_N(_r));
e73f7b5
+		ROW_N(&RES_ROWS(_r)[i]) = ROW_N(&orow_it->hdr);
e73f7b5
+		++i;
e73f7b5
+	}
e73f7b5
+	
e73f7b5
+	for (orow_it = orow_list; orow_it; orow_it = orow_list) {
e73f7b5
+		orow_list = orow_it->next;
e73f7b5
+		pkg_free(orow_it);
e73f7b5
+		orow_it = NULL;
e73f7b5
 	}
e73f7b5
+	return 0;
e73f7b5
+	
e73f7b5
 ora_err:
e73f7b5
 	LM_ERR("driver: %s\n", db_oracle_error(con, status));
e73f7b5
 stop_load:
e73f7b5
-	db_free_rows(_r);
e73f7b5
-	RES_ROW_N(_r) = 0;	/* TODO: skipped in db_res.c :) */
e73f7b5
+	for (orow_it = orow_list; orow_it; orow_it = orow_list) {
e73f7b5
+		orow_list = orow_it->next;
e73f7b5
+		db_free_row(&orow_it->hdr);
e73f7b5
+		pkg_free(orow_it);
e73f7b5
+		orow_it = NULL;
e73f7b5
+	}
e73f7b5
 	return -3;
e73f7b5
 }
e73f7b5
 
e73f7b5
diff --git a/modules/db_oracle/timer.c b/modules/db_oracle/timer.c
e73f7b5
new file mode 100644
e73f7b5
index 0000000..50484f4
e73f7b5
--- /dev/null
e73f7b5
+++ b/modules/db_oracle/timer.c
e73f7b5
@@ -0,0 +1,131 @@
e73f7b5
+#include "timer.h"
e73f7b5
+#include "../../dprint.h"
e73f7b5
+#include "../../sr_module.h"
e73f7b5
+
e73f7b5
+#include <signal.h>
e73f7b5
+#include <stdlib.h>
e73f7b5
+#include <errno.h>
e73f7b5
+#include <sys/time.h>
e73f7b5
+
e73f7b5
+#define MAX_TIMEOUT_S  10
e73f7b5
+#define MIN_TIMEOUT_MCS 100000
e73f7b5
+
e73f7b5
+/* Default is 3.0 second */
e73f7b5
+struct itimerval request_tm = {{0,0}, {3,0}};
e73f7b5
+// unsigned request_tm;
e73f7b5
+
e73f7b5
+/* Default is 0.2 second */
e73f7b5
+struct itimerval restore_tm = {{0,0}, {0,200000}};
e73f7b5
+
e73f7b5
+struct itimerval stop_tm = {{0,0}, {0,0}};
e73f7b5
+
e73f7b5
+/* Simple error handling functions */
e73f7b5
+
e73f7b5
+#define handle_error_en(en, msg) \
e73f7b5
+	do { LM_ERR(msg": %s\n", strerror(en)); return 1; } while (0)
e73f7b5
+	
e73f7b5
+static ora_con_t *g_con;
e73f7b5
+
e73f7b5
+static int set_tv(unsigned type, const char* val, struct timeval* tv)
e73f7b5
+{
e73f7b5
+	char *eptr;
e73f7b5
+	struct itimerval tt;
e73f7b5
+	unsigned long s, ms;
e73f7b5
+	double dv;
e73f7b5
+	
e73f7b5
+	if (type != STR_PARAM) {
e73f7b5
+		LM_ERR("type of parameter is no STR\n");
e73f7b5
+		return -1;
e73f7b5
+	}
e73f7b5
+	
e73f7b5
+	if (!val || !*val) {
e73f7b5
+		LM_ERR("empty parameter\n");
e73f7b5
+		return -1;
e73f7b5
+	}
e73f7b5
+	
e73f7b5
+	errno = 0;
e73f7b5
+	dv = strtod(val, &eptr);
e73f7b5
+	
e73f7b5
+	if (*eptr) {
e73f7b5
+		LM_ERR("invalid parameter string\n");
e73f7b5
+		return -2;
e73f7b5
+	}
e73f7b5
+	
e73f7b5
+	if (   errno
e73f7b5
+		|| dv > (double)MAX_TIMEOUT_S
e73f7b5
+		|| (dv < ((double)MIN_TIMEOUT_MCS)/100000))
e73f7b5
+	{
e73f7b5
+		LM_ERR("value must be between 0.%.6u and %u.0\n",
e73f7b5
+		MIN_TIMEOUT_MCS, MAX_TIMEOUT_S);
e73f7b5
+		return -3;
e73f7b5
+	}
e73f7b5
+	
e73f7b5
+	s = (unsigned)dv;
e73f7b5
+	dv -= (double)s;
e73f7b5
+	ms = (unsigned)(dv * 1000000);
e73f7b5
+	tv->tv_sec = (time_t)s;
e73f7b5
+	tv->tv_usec = (suseconds_t)ms;
e73f7b5
+	return 0;
e73f7b5
+}
e73f7b5
+
e73f7b5
+
e73f7b5
+/*
e73f7b5
+	* set operation timeout
e73f7b5
+	*/
e73f7b5
+int set_timeout(unsigned type, const char* val)
e73f7b5
+{
e73f7b5
+	return set_tv(type, val, &request_tm.it_value);
e73f7b5
+}
e73f7b5
+
e73f7b5
+
e73f7b5
+/*
e73f7b5
+	* set (re)connect timeout
e73f7b5
+	*/
e73f7b5
+int set_reconnect(unsigned type, const char* val)
e73f7b5
+{
e73f7b5
+	return set_tv(type, val, &restore_tm.it_value);
e73f7b5
+}
e73f7b5
+
e73f7b5
+void ora_alarm_handle(int sig) {
e73f7b5
+	LM_INFO("ora_alarm_handle\n");
e73f7b5
+	sword status;
e73f7b5
+	status = OCIBreak(g_con->svchp, g_con->errhp);
e73f7b5
+	if (status != OCI_SUCCESS) {
e73f7b5
+		LM_ERR("OCIBreak: %s\n", db_oracle_error(g_con, status));
e73f7b5
+	}
e73f7b5
+}
e73f7b5
+
e73f7b5
+int init_ora_timer(ora_con_t* con) {
e73f7b5
+	g_con = con;
e73f7b5
+	struct sigaction sa;
e73f7b5
+	memset(&sa, 0, sizeof(sa));
e73f7b5
+	sa.sa_handler = ora_alarm_handle;
e73f7b5
+	if (sigaction(SIGALRM, &sa, NULL) < -1)
e73f7b5
+		handle_error_en(errno, "sigaction");
e73f7b5
+	
e73f7b5
+	return 0;
e73f7b5
+}
e73f7b5
+
e73f7b5
+int destroy_ora_timer()
e73f7b5
+{
e73f7b5
+	timer_stop();
e73f7b5
+}
e73f7b5
+
e73f7b5
+void request_timer()
e73f7b5
+{
e73f7b5
+	if (setitimer(ITIMER_REAL, &request_tm, NULL) < 0)
e73f7b5
+		LM_ERR("setitimer: %s\n", strerror(errno));
e73f7b5
+}
e73f7b5
+
e73f7b5
+void restore_timer()
e73f7b5
+{
e73f7b5
+	if (setitimer(ITIMER_REAL, &restore_tm, NULL) < 0)
e73f7b5
+		LM_ERR("setitimer: %s\n", strerror(errno));
e73f7b5
+}
e73f7b5
+
e73f7b5
+void timer_stop()
e73f7b5
+{
e73f7b5
+	if (setitimer(ITIMER_REAL, &stop_tm, NULL) < 0)
e73f7b5
+		LM_ERR("setitimer: %s\n", strerror(errno));
e73f7b5
+}
e73f7b5
+	
e73f7b5
\ No newline at end of file
e73f7b5
diff --git a/modules/db_oracle/timer.h b/modules/db_oracle/timer.h
e73f7b5
new file mode 100644
e73f7b5
index 0000000..24aa4a9
e73f7b5
--- /dev/null
e73f7b5
+++ b/modules/db_oracle/timer.h
e73f7b5
@@ -0,0 +1,22 @@
e73f7b5
+#ifndef ORA_TIMER_H
e73f7b5
+#define ORA_TIMER_H
e73f7b5
+
e73f7b5
+#include "ora_con.h"
e73f7b5
+
e73f7b5
+/*
e73f7b5
+ * parse timeout value for operation in syntax: nnn.mmm (sec/ms)
e73f7b5
+ */
e73f7b5
+int set_timeout(unsigned type, const char* val);
e73f7b5
+
e73f7b5
+/*
e73f7b5
+ * parse timeout value for reconnect in syntax: nnn.mmm (sec/ms)
e73f7b5
+ */
e73f7b5
+int set_reconnect(unsigned type, const char* val);
e73f7b5
+
e73f7b5
+int init_ora_timer(ora_con_t* con);
e73f7b5
+int destroy_ora_timer();
e73f7b5
+
e73f7b5
+void request_timer();
e73f7b5
+void restore_timer();
e73f7b5
+void timer_stop();
e73f7b5
+#endif // ORA_TIMER_H
e73f7b5
\ No newline at end of file
e73f7b5
-- 
818202b
1.8.1
e73f7b5