Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

dlr_pgsql.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * dlr_pgsql.c
00059  *
00060  * Implementation of handling delivery reports (DLRs)
00061  * for PostgreSQL database
00062  *
00063  * modeled after dlr_mysql.c
00064  *
00065  * Alexander Malysh <a.malysh@centrium.de>, cleanup 2004
00066  */
00067 
00068 #include "gwlib/gwlib.h"
00069 #include "gwlib/dbpool.h"
00070 #include "dlr_p.h"
00071 
00072 
00073 #ifdef HAVE_PGSQL
00074 #include <libpq-fe.h>
00075 
00076 /*
00077  * Our connection pool to pgsql.
00078  */
00079 static DBPool *pool = NULL;
00080 
00081 /*
00082  * Database fields, which we are use.
00083  */
00084 static struct dlr_db_fields *fields = NULL;
00085 
00086 
00087 static inline int pgsql_update(const Octstr *sql)
00088 {
00089     DBPoolConn *pc;
00090     int ret = 0;
00091 
00092 #if defined(DLR_TRACE)
00093     debug("dlr.pgsql", 0, "sql: %s", octstr_get_cstr(sql));
00094 #endif
00095 
00096     pc = dbpool_conn_consume(pool);
00097     if (pc == NULL) {
00098         error(0, "PGSQL: Database pool got no connection! DB update failed!");
00099         return -1;
00100     }
00101 
00102     if ((ret = dbpool_conn_update(pc, sql, NULL)) == -1)
00103         error(0, "PGSQL: DB update failed!");
00104     
00105     dbpool_conn_produce(pc);
00106     return ret;
00107 }
00108 
00109 
00110 static inline List *pgsql_select(const Octstr *sql)
00111 {
00112     DBPoolConn *pc;
00113     List *ret = NULL;
00114 
00115 #if defined(DLR_TRACE)
00116     debug("dlr.pgsql", 0, "sql: %s", octstr_get_cstr(sql));
00117 #endif
00118 
00119     pc = dbpool_conn_consume(pool);
00120     if (pc == NULL) {
00121         error(0, "PGSQL: Database pool got no connection! DB operation failed!");
00122         return NULL;
00123     }
00124 
00125     if (dbpool_conn_select(pc, sql, NULL, &ret) == -1)
00126         error(0, "PGSQL: Select failed!");
00127     
00128     dbpool_conn_produce(pc);
00129     return ret;
00130 }
00131 
00132 
00133 static void dlr_pgsql_shutdown()
00134 {
00135     dbpool_destroy(pool);
00136     dlr_db_fields_destroy(fields);
00137 }
00138 
00139 
00140 static void dlr_pgsql_add(struct dlr_entry *entry)
00141 {
00142     Octstr *sql;
00143 
00144     sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES "
00145                         "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');",
00146                         octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
00147                         octstr_get_cstr(fields->field_ts),
00148                         octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst),
00149                         octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url),
00150                         octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc),
00151                         octstr_get_cstr(fields->field_status),
00152                         octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source),
00153                         octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url),
00154                         entry->mask, octstr_get_cstr(entry->boxc_id), 0);
00155 
00156 
00157     pgsql_update(sql);
00158     
00159     octstr_destroy(sql);
00160     dlr_entry_destroy(entry);
00161 }
00162 
00163 
00164 static struct dlr_entry *dlr_pgsql_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
00165 {
00166     struct dlr_entry *res = NULL;
00167     Octstr *sql;
00168     List *result, *row;
00169 
00170     sql = octstr_format("SELECT %s, %s, %s, %s, %s, %s FROM %s WHERE %s='%s' AND %s='%s' LIMIT 1;",
00171                         octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_serv),
00172                         octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_src),
00173                         octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_boxc),
00174                         octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
00175                         octstr_get_cstr(smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
00176 
00177 
00178     result = pgsql_select(sql);
00179     octstr_destroy(sql);
00180 
00181     if (result == NULL || gwlist_len(result) < 1) {
00182         debug("dlr.pgsql", 0, "no rows found");
00183         while((row = gwlist_extract_first(result)))
00184             gwlist_destroy(row, octstr_destroy_item);
00185         gwlist_destroy(result, NULL);
00186         return NULL;
00187     }
00188     
00189     row = gwlist_get(result, 0);
00190 
00191     debug("dlr.pgsql", 0, "Found entry, col1=%s, col2=%s, col3=%s, col4=%s, col5=%s col6=%s",
00192             octstr_get_cstr(gwlist_get(row, 0)),
00193             octstr_get_cstr(gwlist_get(row, 1)),
00194             octstr_get_cstr(gwlist_get(row, 2)),
00195             octstr_get_cstr(gwlist_get(row, 3)),
00196             octstr_get_cstr(gwlist_get(row, 4)),
00197             octstr_get_cstr(gwlist_get(row, 5))
00198      );
00199 
00200     res = dlr_entry_create();
00201     gw_assert(res != NULL);
00202     res->mask        = atoi(octstr_get_cstr(gwlist_get(row, 0)));
00203     res->service     = octstr_duplicate(gwlist_get(row, 1));
00204     res->url         = octstr_duplicate(gwlist_get(row, 2));
00205     res->source      = octstr_duplicate(gwlist_get(row, 3));
00206     res->destination = octstr_duplicate(gwlist_get(row, 4));
00207     res->boxc_id     = octstr_duplicate(gwlist_get(row, 5));
00208     res->smsc        = octstr_duplicate(smsc);
00209 
00210     while((row = gwlist_extract_first(result)))
00211         gwlist_destroy(row, octstr_destroy_item);
00212     gwlist_destroy(result, NULL);
00213     
00214     return res;
00215 }
00216 
00217 
00218 static void dlr_pgsql_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
00219 {
00220     Octstr *sql;
00221 
00222     debug("dlr.pgsql", 0, "removing DLR from database");
00223     sql = octstr_format("DELETE FROM %s WHERE oid = (SELECT oid FROM %s WHERE %s='%s' AND %s='%s' LIMIT 1);",
00224                         octstr_get_cstr(fields->table), octstr_get_cstr(fields->table),
00225                         octstr_get_cstr(fields->field_smsc),
00226                         octstr_get_cstr(smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
00227 
00228 
00229     pgsql_update(sql);
00230     octstr_destroy(sql);
00231 }
00232 
00233 
00234 static void dlr_pgsql_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status)
00235 {
00236     Octstr *sql;
00237 
00238     debug("dlr.pgsql", 0, "updating DLR status in database");
00239     sql = octstr_format("UPDATE %s SET %s=%d WHERE oid = (SELECT oid FROM %s WHERE %s='%s' AND %s='%s' LIMIT 1);",
00240                         octstr_get_cstr(fields->table),
00241                         octstr_get_cstr(fields->field_status), status,
00242                         octstr_get_cstr(fields->table),
00243                         octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
00244                         octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
00245     pgsql_update(sql);
00246     octstr_destroy(sql);
00247 }
00248 
00249 
00250 static long dlr_pgsql_messages(void)
00251 {
00252     Octstr *sql;
00253     long ret;
00254     List *res;
00255 
00256     sql = octstr_format("SELECT count(*) FROM %s;", octstr_get_cstr(fields->table));
00257 
00258     res = pgsql_select(sql);
00259     octstr_destroy(sql);
00260 
00261     if (res == NULL || gwlist_len(res) < 1) {
00262         error(0, "PGSQL: Could not get count of DLR table");
00263         ret = -1;
00264     } else {
00265         ret = atol(octstr_get_cstr(gwlist_get(gwlist_get(res, 0), 0)));
00266     }
00267 
00268     gwlist_destroy(gwlist_extract_first(res), octstr_destroy_item);
00269     gwlist_destroy(res, NULL);
00270         
00271     return ret;
00272 }
00273 
00274 
00275 static void dlr_pgsql_flush(void)
00276 {
00277     Octstr *sql;
00278 
00279     sql = octstr_format("DELETE FROM %s;", octstr_get_cstr(fields->table));
00280 
00281     pgsql_update(sql);
00282     octstr_destroy(sql);
00283 }
00284 
00285 
00286 static struct dlr_storage handles = {
00287     .type = "pgsql",
00288     .dlr_add = dlr_pgsql_add,
00289     .dlr_get = dlr_pgsql_get,
00290     .dlr_update = dlr_pgsql_update,
00291     .dlr_remove = dlr_pgsql_remove,
00292     .dlr_shutdown = dlr_pgsql_shutdown,
00293     .dlr_messages = dlr_pgsql_messages,
00294     .dlr_flush = dlr_pgsql_flush
00295 };
00296 
00297 
00298 struct dlr_storage *dlr_init_pgsql(Cfg *cfg)
00299 {
00300     CfgGroup *grp;
00301     List *grplist;
00302     Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id;
00303     long pgsql_port = 0;
00304     Octstr *p = NULL;
00305     long pool_size;
00306     DBConf *db_conf = NULL;
00307 
00308     /*
00309      * check for all mandatory directives that specify the field names
00310      * of the table used
00311      */
00312     if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))))
00313         panic(0, "DLR: PgSQL: group 'dlr-db' is not specified!");
00314 
00315     if (!(pgsql_id = cfg_get(grp, octstr_imm("id"))))
00316         panic(0, "DLR: PgSQL: directive 'id' is not specified!");
00317 
00318     fields = dlr_db_fields_create(grp);
00319     gw_assert(fields != NULL);
00320 
00321     /*
00322      * now grap the required information from the 'pgsql-connection' group
00323      * with the pgsql-id we just obtained
00324      *
00325      * we have to loop through all available PostgreSQL connection definitions
00326      * and search for the one we are looking for
00327      */
00328 
00329     grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection"));
00330     while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
00331         p = cfg_get(grp, octstr_imm("id"));
00332         if (p != NULL && octstr_compare(p, pgsql_id) == 0) {
00333             goto found;
00334         }
00335         if (p != NULL) 
00336             octstr_destroy(p);
00337     }
00338     panic(0, "DLR: PgSQL: connection settings for id '%s' are not specified!",
00339           octstr_get_cstr(pgsql_id));
00340 
00341 found:
00342     octstr_destroy(p);
00343     gwlist_destroy(grplist, NULL);
00344 
00345     if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
00346         pool_size = 1;
00347 
00348     if (!(pgsql_host = cfg_get(grp, octstr_imm("host"))))
00349         panic(0, "DLR: PgSQL: directive 'host' is not specified!");
00350     if (!(pgsql_user = cfg_get(grp, octstr_imm("username"))))
00351         panic(0, "DLR: PgSQL: directive 'username' is not specified!");
00352     if (!(pgsql_pass = cfg_get(grp, octstr_imm("password"))))
00353         panic(0, "DLR: PgSQL: directive 'password' is not specified!");
00354     if (!(pgsql_db = cfg_get(grp, octstr_imm("database"))))
00355         panic(0, "DLR: PgSQL: directive 'database' is not specified!");
00356     cfg_get_integer(&pgsql_port, grp, octstr_imm("port"));  /* optional */
00357 
00358     /*
00359      * ok, ready to connect to the database
00360      */
00361     db_conf = gw_malloc(sizeof(DBConf));
00362     gw_assert(db_conf != NULL);
00363 
00364     db_conf->pgsql = gw_malloc(sizeof(PgSQLConf));
00365     gw_assert(db_conf->pgsql != NULL);
00366 
00367     db_conf->pgsql->host = pgsql_host;
00368     db_conf->pgsql->port = pgsql_port;
00369     db_conf->pgsql->username = pgsql_user;
00370     db_conf->pgsql->password = pgsql_pass;
00371     db_conf->pgsql->database = pgsql_db;
00372 
00373     pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size);
00374     gw_assert(pool != NULL);
00375 
00376     /*
00377      * XXX should a failing connect throw panic?!
00378      */
00379     if (dbpool_conn_count(pool) == 0)
00380         panic(0,"DLR: PgSQL: database pool has no connections!");
00381 
00382     octstr_destroy(pgsql_id);
00383 
00384     return &handles;
00385 }
00386 #else
00387 /*
00388  * Return NULL , so we point dlr-core that we were
00389  * not compiled in.
00390  */
00391 struct dlr_storage *dlr_init_pgsql(Cfg* cfg)
00392 {
00393     return NULL;
00394 }
00395 #endif /* HAVE_PGSQL */
00396 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.