con.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: con.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * UNIXODBC module
00005  *
00006  * Copyright (C) 2005-2006 Marco Lorrai
00007  * Copyright (C) 2008 1&1 Internet AG
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  *
00026  * History:
00027  * --------
00028  *  2005-12-01  initial commit (chgen)
00029  *  2006-01-10  UID (username) and PWD (password) attributes added to 
00030  *              connection string (bogdan)
00031  *  2006-05-05  extract_error passes back last error state on return (sgupta)
00032  */
00033 
00034 #include "con.h"
00035 #include "../../mem/mem.h"
00036 #include "../../dprint.h"
00037 #include "../../ut.h"
00038 #include <time.h>
00039 
00040 #define DSN_ATTR  "DSN="
00041 #define DSN_ATTR_LEN  (sizeof(DSN_ATTR)-1)
00042 #define UID_ATTR  "UID="
00043 #define UID_ATTR_LEN  (sizeof(UID_ATTR)-1)
00044 #define PWD_ATTR  "PWD="
00045 #define PWD_ATTR_LEN  (sizeof(PWD_ATTR)-1)
00046 
00047 
00048 char *db_unixodbc_build_conn_str(const struct db_id* id, char *buf)
00049 {
00050    int len, ld, lu, lp;
00051    char *p;
00052 
00053    if (!buf) return 0;
00054 
00055    ld = id->database?strlen(id->database):0;
00056    lu = id->username?strlen(id->username):0;
00057    lp = id->password?strlen(id->password):0;
00058 
00059    len = (ld?(DSN_ATTR_LEN + ld + 1):0)
00060       + (lu?(UID_ATTR_LEN + lu + 1):0)
00061       + PWD_ATTR_LEN + lp + 1;
00062 
00063    if ( len>=MAX_CONN_STR_LEN ){
00064       LM_ERR("connection string too long! Increase MAX_CONN_STR_LEN"
00065             " and recompile\n");
00066       return 0;
00067    }
00068 
00069    p = buf;
00070    if (ld) {
00071       memcpy( p , DSN_ATTR, DSN_ATTR_LEN);
00072       p += DSN_ATTR_LEN;
00073       memcpy( p, id->database, ld);
00074       p += ld;
00075    }
00076    if (lu) {
00077       *(p++) = ';';
00078       memcpy( p , UID_ATTR, UID_ATTR_LEN);
00079       p += UID_ATTR_LEN;
00080       memcpy( p, id->username, lu);
00081       p += lu;
00082    }
00083    if (lp) {
00084       *(p++) = ';';
00085       memcpy( p , PWD_ATTR, PWD_ATTR_LEN);
00086       p += PWD_ATTR_LEN;
00087       memcpy( p, id->password, lp);
00088       p += lp;
00089    }
00090    *(p++) = ';';
00091    *p = 0 ; /* make it null terminated */
00092 
00093    return buf;
00094 }
00095 
00096 
00097 /*
00098  * Create a new connection structure,
00099  * open the UNIXODBC connection and set reference count to 1
00100  */
00101 struct my_con* db_unixodbc_new_connection(struct db_id* id)
00102 {
00103    SQLCHAR outstr[1024];
00104    SQLSMALLINT outstrlen;
00105    int ret;
00106    struct my_con* ptr;
00107    char conn_str[MAX_CONN_STR_LEN];
00108 
00109    if (!id)
00110    {
00111       LM_ERR("invalid parameter value\n");
00112       return 0;
00113    }
00114 
00115    ptr = (struct my_con*)pkg_malloc(sizeof(struct my_con));
00116    if (!ptr)
00117    {
00118       LM_ERR("no more memory left\n");
00119       return 0;
00120    }
00121 
00122    memset(ptr, 0, sizeof(struct my_con));
00123    ptr->ref = 1;
00124    // allocate environment handle
00125    ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(ptr->env));
00126    if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
00127    {
00128       LM_ERR("could not alloc a SQL handle\n");
00129       if (ptr) pkg_free(ptr);
00130       return 0;
00131    }
00132    // set the environment
00133    ret = SQLSetEnvAttr(ptr->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
00134    if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
00135    {
00136       LM_ERR("could not set the environment\n");
00137       goto err1;
00138    }
00139    // allocate connection handle
00140    ret = SQLAllocHandle(SQL_HANDLE_DBC, ptr->env, &(ptr->dbc));
00141    if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO))
00142    {
00143       LM_ERR("could not alloc a connection handle %d\n", ret);
00144       goto err1;
00145    }
00146 
00147    if (!db_unixodbc_build_conn_str(id, conn_str)) {
00148       LM_ERR("failed to build connection string\n");
00149       goto err2;
00150    }
00151 
00152    LM_DBG("opening connection: unixodbc://xxxx:xxxx@%s/%s\n", ZSW(id->host),
00153       ZSW(id->database));
00154 
00155    ret = SQLDriverConnect(ptr->dbc, NULL, (SQLCHAR*)conn_str, SQL_NTS,
00156       outstr, sizeof(outstr), &outstrlen,
00157       SQL_DRIVER_COMPLETE);
00158    if (SQL_SUCCEEDED(ret))
00159    {
00160       LM_DBG("connection succeeded with reply <%s>\n", outstr);
00161       if (ret == SQL_SUCCESS_WITH_INFO)
00162       {
00163          LM_DBG("driver reported the following diagnostics\n");
00164          db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
00165       }
00166    }
00167    else
00168    {
00169       LM_ERR("failed to connect\n");
00170       db_unixodbc_extract_error("SQLDriverConnect", ptr->dbc, SQL_HANDLE_DBC, NULL);
00171       goto err2;
00172    }
00173 
00174    ptr->stmt_handle = NULL;
00175 
00176    ptr->timestamp = time(0);
00177    ptr->id = id;
00178    return ptr;
00179 
00180 err1:
00181    SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
00182    if (ptr) pkg_free(ptr);
00183    return 0;
00184 
00185 err2:
00186    SQLFreeHandle(SQL_HANDLE_ENV, &(ptr->env));
00187    SQLFreeHandle(SQL_HANDLE_DBC, &(ptr->dbc));
00188    if (ptr) pkg_free(ptr);
00189    return 0;
00190 }
00191 
00192 /*
00193  * Close the connection and release memory
00194  */
00195 void db_unixodbc_free_connection(struct my_con* con)
00196 {
00197    if (!con) return;
00198    SQLFreeHandle(SQL_HANDLE_ENV, con->env);
00199    SQLDisconnect(con->dbc);
00200    SQLFreeHandle(SQL_HANDLE_DBC, con->dbc);
00201    pkg_free(con);
00202 }
00203 
00204 
00205 void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQLSMALLINT type, char* stret)
00206 {
00207    SQLINTEGER   i = 0;
00208    SQLINTEGER   native;
00209    SQLCHAR  state[ 7 ];
00210    SQLCHAR  text[256];
00211    SQLSMALLINT  len;
00212    SQLRETURN   ret;
00213 
00214    do
00215    {
00216       ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
00217          sizeof(text), &len );
00218       if (SQL_SUCCEEDED(ret)) {
00219          LM_ERR("unixodbc:%s=%s:%ld:%ld:%s\n", fn, state, (long)i, 
00220                (long)native, text);
00221          if(stret) strcpy( stret, (char*)state );
00222       }
00223    }
00224    while( ret == SQL_SUCCESS );
00225 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6