ora_con.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007,2008 TRUNK MOBILE
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 #include <string.h>
00024 #include <stdio.h>
00025 #include "../../mem/mem.h"
00026 #include "../../dprint.h"
00027 #include "asynch.h"
00028 #include "ora_con.h"
00029 
00030 /*************************************************************************/
00031 /*
00032  * Create a new connection structure,
00033  * open the Oracle connection and set reference count to 1
00034  */
00035 ora_con_t* db_oracle_new_connection(const struct db_id* id)
00036 {
00037    ora_con_t* con;
00038    char buf[512];
00039    size_t uri_len;
00040    sword status;
00041 
00042    if (!id || !id->username || !*id->username || !id->password ||
00043       !*id->password || !id->database || !*id->database)
00044    {
00045 bad_param:
00046       LM_ERR("invalid parameter value\n");
00047       return NULL;
00048    }
00049 
00050 
00051    if (!id->host || !*id->host) {
00052       if (id->port) goto bad_param;
00053       uri_len = snprintf(buf, sizeof(buf), "%s", id->database);
00054    } else if (id->port) {
00055       uri_len = snprintf(buf, sizeof(buf), "%s:%u/%s",
00056             id->host, id->port, id->database);
00057    } else {
00058       uri_len = snprintf(buf, sizeof(buf), "%s/%s",
00059             id->host, id->database);
00060    }
00061    if (uri_len >= sizeof(buf)) goto bad_param;
00062    LM_DBG("opening connection: oracle://xxxx:xxxx@%s\n", buf);
00063 
00064    con = (ora_con_t*)pkg_malloc(sizeof(*con) + uri_len+1);
00065    if (!con) {
00066       LM_ERR("no private memory left\n");
00067       return NULL;
00068    }
00069 
00070    memset(con, 0, sizeof(*con));
00071    con->hdr.ref = 1;
00072    con->hdr.id = (struct db_id*)id; /* set here - freed on error */
00073    con->uri_len = uri_len;
00074    memcpy(con->uri, buf, uri_len+1);
00075 
00076    if (   OCIEnvCreate(&con->envhp,
00077          OCI_DEFAULT | OCI_NEW_LENGTH_SEMANTICS,
00078                   NULL, NULL, NULL, NULL, 0, NULL) != OCI_SUCCESS
00079        || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->errhp,
00080           OCI_HTYPE_ERROR, 0, NULL) != OCI_SUCCESS
00081        || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->srvhp,
00082           OCI_HTYPE_SERVER, 0, NULL) != OCI_SUCCESS
00083        || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->svchp,
00084           OCI_HTYPE_SVCCTX, 0, NULL) != OCI_SUCCESS
00085        || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->authp,
00086              OCI_HTYPE_SESSION, 0, NULL) != OCI_SUCCESS)
00087    {
00088 
00089       LM_ERR("no oracle memory left\n");
00090       db_oracle_free_connection(con);
00091       return NULL;
00092    }
00093 
00094    status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->srvhp, 0,
00095          OCI_ATTR_SERVER, con->errhp);
00096    if (status != OCI_SUCCESS) goto connect_err;
00097    status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
00098                  id->username, (ub4)strlen(id->username),
00099                  OCI_ATTR_USERNAME, con->errhp);
00100    if (status != OCI_SUCCESS) goto connect_err;
00101    status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
00102                  id->password, (ub4)strlen(id->password),
00103                  OCI_ATTR_PASSWORD, con->errhp);
00104    if (status != OCI_SUCCESS) goto connect_err;
00105    status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->authp, 0,
00106                    OCI_ATTR_SESSION, con->errhp);
00107    if (status != OCI_SUCCESS) goto connect_err;
00108    status = db_oracle_reconnect(con);
00109    if (status != OCI_SUCCESS) {
00110 connect_err:
00111       if (   (status != OCI_ERROR && status != OCI_SUCCESS_WITH_INFO)
00112           || OCIErrorGet(con->errhp, 1, NULL, &status, (OraText*)buf,
00113              sizeof(buf), OCI_HTYPE_ERROR) != OCI_SUCCESS)
00114       {
00115          LM_ERR("internal driver error\n");
00116       } else {
00117          LM_ERR("driver: %s\n", buf);
00118       }
00119 drop_connection:
00120       db_oracle_free_connection(con);
00121       return NULL;
00122    }
00123 
00124    // timelimited operation
00125    status = begin_timelimit(con, 0);
00126    if (status != OCI_SUCCESS) goto connect_err;
00127    do status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf,
00128       (ub4)sizeof(buf), OCI_HTYPE_SVCCTX);
00129    while (wait_timelimit(con, status));
00130    if (done_timelimit(con, status)) goto drop_connection;
00131    if (status != OCI_SUCCESS) goto connect_err;
00132    LM_INFO("server version is %s\n", buf);
00133    return con;
00134 }
00135 
00136 
00137 /*
00138  * Close the connection and release memory
00139  */
00140 void db_oracle_free_connection(ora_con_t* con)
00141 {
00142    if (!con) return;
00143 
00144    if (con->connected)
00145       db_oracle_disconnect(con);
00146    if (con->svchp)
00147       OCIHandleFree(con->svchp, OCI_HTYPE_SVCCTX);
00148    if (con->authp)
00149       OCIHandleFree(con->authp, OCI_HTYPE_SESSION);
00150    if (con->srvhp)
00151       OCIHandleFree(con->srvhp, OCI_HTYPE_SERVER);
00152    if (con->errhp)
00153       OCIHandleFree(con->errhp, OCI_HTYPE_ERROR);
00154    if (con->envhp)
00155       OCIHandleFree(con->envhp, OCI_HTYPE_ENV);
00156    free_db_id(con->hdr.id);
00157    pkg_free(con);
00158 }
00159 
00160 
00161 /*
00162  * Disconnect after network error
00163  */
00164 void db_oracle_disconnect(ora_con_t* con)
00165 {
00166    sword status;
00167 
00168    switch (con->connected) {
00169    default:
00170       status = OCISessionEnd(con->svchp, con->errhp, con->authp,
00171          OCI_DEFAULT);
00172       if (status != OCI_SUCCESS)
00173          LM_ERR("driver: %s\n", db_oracle_error(con, status));
00174    case 1:
00175       status = OCIServerDetach(con->srvhp, con->errhp, OCI_DEFAULT);
00176       if (status != OCI_SUCCESS)
00177          LM_ERR("driver: %s\n", db_oracle_error(con, status));
00178       con->connected = 0;
00179    case 0:
00180       break;
00181    }
00182 }
00183 
00184 
00185 /*
00186  * Reconnect to server (after error)
00187  */
00188 sword db_oracle_reconnect(ora_con_t* con)
00189 {
00190    sword status;
00191 
00192    if (con->connected)
00193       db_oracle_disconnect(con);
00194 
00195    /* timelimited operation, but OCI tcp-network does not support it :( */
00196    status = OCIServerAttach(con->srvhp, con->errhp, (OraText*)con->uri,
00197       con->uri_len, 0);
00198    if (status == OCI_SUCCESS) {
00199       ++con->connected;
00200       /*
00201        * timelimited operation, but OCI has BUG in asynch
00202        * implementation of OCISessionBegin :(.
00203        *
00204        * Next code is 'empiric hack' that work (tested) in v10/v11.
00205        */
00206       status = begin_timelimit(con, 1);
00207       if (status != OCI_SUCCESS) goto done;
00208       status = OCISessionBegin(con->svchp, con->errhp, con->authp,
00209          OCI_CRED_RDBMS, OCI_DEFAULT);
00210       while (wait_timelimit(con, status)) {
00211          sword code;
00212 
00213          status = OCIServerVersion(con->svchp, con->errhp, NULL,
00214             0, OCI_HTYPE_SVCCTX);
00215 
00216          if (   status != OCI_ERROR
00217              || OCIErrorGet(con->errhp, 1, NULL, &code, NULL, 0,
00218                  OCI_HTYPE_ERROR) != OCI_SUCCESS) break;
00219          switch (code) {
00220          case 24909: /* other call in progress */
00221             status = OCI_STILL_EXECUTING;
00222             continue;
00223 
00224          case 3127:  /* no new operation until active ends */
00225             status = OCISessionBegin(con->svchp, con->errhp,
00226                con->authp, OCI_CRED_RDBMS, OCI_DEFAULT);
00227          default:
00228             break;
00229          }
00230          break;
00231       }
00232       if (done_timelimit(con, status)) goto done;
00233 
00234       if (status == OCI_SUCCESS)
00235          ++con->connected;
00236    }
00237 done:
00238    return status;
00239 }

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