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

dlr_sdb.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_sdb.c
00059  *
00060  * Implementation of handling delivery reports (DLRs)
00061  * for LibSDB.
00062  *
00063  * Andreas Fink <andreas@fink.org>, 18.08.2001
00064  * Stipe Tolj <stolj@wapme.de>, 22.03.2002
00065  * Alexander Malysh <a.malysh@centrium.de> 2003
00066  * Guillaume Cottenceau 2004 (dbpool support)
00067 */
00068 
00069 #include "gwlib/gwlib.h"
00070 #include "gwlib/dbpool.h"
00071 #include "dlr_p.h"
00072 
00073 #ifdef HAVE_SDB
00074 #include <sdb.h>
00075 
00076 /*
00077  * Our connection pool to sdb.
00078  */
00079 static DBPool *pool = NULL;
00080 
00081 /*
00082  * Database fields, which we use.
00083  */
00084 static struct dlr_db_fields *fields = NULL;
00085 
00086 enum {
00087     SDB_ORACLE,
00088     SDB_MYSQL,
00089     SDB_POSTGRES,
00090     SDB_OTHER
00091 };
00092 
00093 static long sdb_conn_type = SDB_OTHER;
00094 
00095 
00096 static const char* sdb_get_limit_str()
00097 {
00098     switch (sdb_conn_type) {
00099         case SDB_ORACLE:
00100             return "AND ROWNUM < 2";
00101         case SDB_MYSQL:
00102         case SDB_POSTGRES:
00103             return "LIMIT 1";
00104         case SDB_OTHER:
00105         default:
00106             return "";
00107     }
00108 }
00109 
00110 static void dlr_sdb_shutdown()
00111 {
00112     dbpool_destroy(pool);
00113     dlr_db_fields_destroy(fields);
00114 }
00115 
00116 static int gw_sdb_query(char *query,
00117                         int (*callback)(int, char **, void *), void *closure)
00118 {
00119     DBPoolConn *pc;
00120     int rows;
00121 
00122     pc = dbpool_conn_consume(pool);
00123     if (pc == NULL) {
00124         error(0, "SDB: Database pool got no connection!");
00125         return -1;
00126     }
00127 
00128     rows = sdb_query(pc->conn, query, callback, closure);
00129 
00130     dbpool_conn_produce(pc);
00131 
00132     return rows;
00133 }
00134 
00135 static void dlr_sdb_add(struct dlr_entry *dlr)
00136 {
00137     Octstr *sql;
00138     int state;
00139 
00140     sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES "
00141                         "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d')",
00142                         octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
00143                         octstr_get_cstr(fields->field_ts),
00144                         octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst),
00145                         octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url),
00146                         octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc),
00147                         octstr_get_cstr(fields->field_status),
00148                         octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp),
00149                         octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination),
00150                         octstr_get_cstr(dlr->service), octstr_get_cstr(dlr->url), dlr->mask,
00151                         octstr_get_cstr(dlr->boxc_id), 0);
00152 
00153 #if defined(DLR_TRACE)
00154      debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
00155 #endif
00156 
00157     state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL);
00158     if (state == -1)
00159         error(0, "SDB: error in inserting DLR for DST <%s>", octstr_get_cstr(dlr->destination));
00160 
00161     octstr_destroy(sql);
00162     dlr_entry_destroy(dlr);
00163 }
00164 
00165 static int sdb_callback_add(int n, char **p, void *data)
00166 {
00167     struct dlr_entry *res = (struct dlr_entry *) data;
00168 
00169     if (n != 6) {
00170         debug("dlr.sdb", 0, "SDB: Result has incorrect number of columns: %d", n);
00171         return 0;
00172     }
00173 
00174 #if defined(DLR_TRACE)
00175     debug("dlr.sdb", 0, "row=%s,%s,%s,%s,%s,%s",p[0],p[1],p[2],p[3],p[4],p[5]);
00176 #endif
00177 
00178     if (res->destination != NULL) {
00179         debug("dlr.sdb", 0, "SDB: Row already stored.");
00180         return 0;
00181     }
00182 
00183     res->mask = atoi(p[0]);
00184     res->service = octstr_create(p[1]);
00185     res->url = octstr_create(p[2]);
00186     res->source = octstr_create(p[3]);
00187     res->destination = octstr_create(p[4]);
00188     res->boxc_id = octstr_create(p[5]);
00189 
00190     return 0;
00191 }
00192 
00193 static int sdb_callback_msgs(int n, char **p, void *data)
00194 {
00195     long *count = (long *) data;
00196 
00197     if (n != 1) {
00198         debug("dlr.sdb", 0, "SDB: Result has incorrect number of columns: %d", n);
00199         return 0;
00200     }
00201 
00202 #if defined(DLR_TRACE)
00203     debug("dlr.sdb", 0, "SDB: messages=%s",p[0]);
00204 #endif
00205 
00206     *count = atol(p[0]);
00207 
00208     return 0;
00209 }
00210 
00211 static struct dlr_entry*  dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
00212 {
00213     Octstr *sql;
00214     int state;
00215     struct dlr_entry *res = dlr_entry_create();
00216 
00217     gw_assert(res != NULL);
00218 
00219     sql = octstr_format("SELECT %s, %s, %s, %s, %s, %s FROM %s WHERE %s='%s' AND %s='%s' %s",
00220                         octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_serv),
00221                         octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_src),
00222                         octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_boxc),
00223                         octstr_get_cstr(fields->table),
00224                         octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
00225                         octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts), sdb_get_limit_str());
00226 
00227 #if defined(DLR_TRACE)
00228      debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
00229 #endif
00230 
00231     state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res);
00232     octstr_destroy(sql);
00233     if (state == -1) {
00234         error(0, "SDB: error in finding DLR");
00235         goto notfound;
00236     }
00237     else if (state == 0) {
00238         debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst));
00239         goto notfound;
00240     }
00241 
00242     res->smsc = octstr_duplicate(smsc);
00243 
00244     return res;
00245 
00246 notfound:
00247     dlr_entry_destroy(res);
00248     return NULL;
00249 }
00250 
00251 static void  dlr_sdb_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status)
00252 {
00253     Octstr *sql;
00254     int state;
00255 
00256     debug("dlr.sdb", 0, "SDB: updating DLR status in database");
00257     sql = octstr_format("UPDATE %s SET %s=%d WHERE %s='%s' AND %s='%s' %s",
00258                         octstr_get_cstr(fields->table),
00259                         octstr_get_cstr(fields->field_status), status,
00260                         octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
00261                         octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts), sdb_get_limit_str());
00262 
00263 #if defined(DLR_TRACE)
00264      debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
00265 #endif
00266 
00267     state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL);
00268     octstr_destroy(sql);
00269     if (state == -1) {
00270         error(0, "SDB: error in updating DLR");
00271     }
00272 }
00273 
00274 static void  dlr_sdb_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
00275 {
00276     Octstr *sql;
00277     int state;
00278 
00279     debug("dlr.sdb", 0, "removing DLR from database");
00280     if (sdb_conn_type == SDB_POSTGRES) {
00281         /*
00282          * Postgres doesn't support limiting delete/update queries,
00283          * thus we need to use a select subquery.
00284          * - notice that for uniqueness use of `oid', postgres suggests
00285          * to do vacuum regularly, even if it's virtually impossible
00286          * to hit duplicates since oid's are given in a row
00287          */
00288         sql = octstr_format("DELETE FROM %s WHERE oid = \
00289                             (SELECT oid FROM %s WHERE %s='%s' AND %s='%s' LIMIT 1)",
00290                             octstr_get_cstr(fields->table),
00291                             octstr_get_cstr(fields->table),
00292                             octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
00293                             octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
00294     } else {
00295         sql = octstr_format("DELETE FROM %s WHERE %s='%s' AND %s='%s' %s",
00296                             octstr_get_cstr(fields->table),
00297                             octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
00298                             octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts), sdb_get_limit_str());
00299     }
00300 
00301 #if defined(DLR_TRACE)
00302      debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
00303 #endif
00304 
00305     state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL);
00306     octstr_destroy(sql);
00307     if (state == -1)
00308         error(0, "SDB: error in deleting DLR");
00309 }
00310 
00311 static long dlr_sdb_messages(void)
00312 {
00313     Octstr *sql;
00314     int state;
00315     long res = 0;
00316 
00317     sql = octstr_format("SELECT count(*) FROM %s", octstr_get_cstr(fields->table));
00318 
00319 #if defined(DLR_TRACE)
00320     debug("dlr.sdb", 0, "sql: %s", octstr_get_cstr(sql));
00321 #endif
00322 
00323     state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_msgs, &res);
00324     octstr_destroy(sql);
00325     if (state == -1) {
00326         error(0, "SDB: error in selecting ammount of waiting DLRs");
00327         return -1;
00328     }
00329 
00330     return res;
00331 }
00332 
00333 static void dlr_sdb_flush(void)
00334 {
00335     Octstr *sql;
00336     int state;
00337 
00338     sql = octstr_format("DELETE FROM %s", octstr_get_cstr(fields->table));
00339 
00340 #if defined(DLR_TRACE)
00341      debug("dlr.sdb", 0, "sql: %s", octstr_get_cstr(sql));
00342 #endif
00343 
00344     state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL);
00345     octstr_destroy(sql);
00346     if (state == -1) {
00347         error(0, "SDB: error in flusing DLR table");
00348     }
00349 }
00350 
00351 
00352 static struct dlr_storage  handles = {
00353     .type = "sdb",
00354     .dlr_add = dlr_sdb_add,
00355     .dlr_get = dlr_sdb_get,
00356     .dlr_update = dlr_sdb_update,
00357     .dlr_remove = dlr_sdb_remove,
00358     .dlr_shutdown = dlr_sdb_shutdown,
00359     .dlr_messages = dlr_sdb_messages,
00360     .dlr_flush = dlr_sdb_flush
00361 };
00362 
00363 struct dlr_storage *dlr_init_sdb(Cfg* cfg)
00364 {
00365     CfgGroup *grp;
00366     List *grplist;
00367     Octstr *sdb_url, *sdb_id;
00368     Octstr *p = NULL;
00369     long pool_size;
00370     DBConf *db_conf = NULL;
00371 
00372     /*
00373      * check for all mandatory directives that specify the field names
00374      * of the used table
00375      */
00376     if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))))
00377         panic(0, "DLR: SDB: group 'dlr-db' is not specified!");
00378 
00379     if (!(sdb_id = cfg_get(grp, octstr_imm("id"))))
00380         panic(0, "DLR: SDB: directive 'id' is not specified!");
00381 
00382     fields = dlr_db_fields_create(grp);
00383     gw_assert(fields != NULL);
00384 
00385     /*
00386      * now grap the required information from the 'mysql-connection' group
00387      * with the sdb-id we just obtained
00388      *
00389      * we have to loop through all available SDB connection definitions
00390      * and search for the one we are looking for
00391      */
00392 
00393     grplist = cfg_get_multi_group(cfg, octstr_imm("sdb-connection"));
00394     while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
00395         p = cfg_get(grp, octstr_imm("id"));
00396         if (p != NULL && octstr_compare(p, sdb_id) == 0) {
00397             goto found;
00398         }
00399         if (p != NULL) octstr_destroy(p);
00400     }
00401     panic(0, "DLR: SDB: connection settings for id '%s' are not specified!",
00402           octstr_get_cstr(sdb_id));
00403 
00404 found:
00405     octstr_destroy(p);
00406     gwlist_destroy(grplist, NULL);
00407 
00408     if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
00409         pool_size = 1;
00410 
00411     if (!(sdb_url = cfg_get(grp, octstr_imm("url"))))
00412         panic(0, "DLR: SDB: directive 'url' is not specified!");
00413 
00414     if (octstr_search(sdb_url, octstr_imm("oracle:"), 0) == 0)
00415         sdb_conn_type = SDB_ORACLE;
00416     else if (octstr_search(sdb_url, octstr_imm("mysql:"), 0) == 0) {
00417         warning(0, "DLR[sdb]: Please use native MySQL support, instead of libsdb.");
00418         sdb_conn_type = SDB_MYSQL;
00419     }
00420     else if (octstr_search(sdb_url, octstr_imm("postgres:"), 0) == 0) {
00421         sdb_conn_type = SDB_POSTGRES;
00422     }
00423     else
00424         sdb_conn_type = SDB_OTHER;
00425 
00426     /*
00427      * ok, ready to connect
00428      */
00429     info(0,"Connecting to sdb resource <%s>.", octstr_get_cstr(sdb_url));
00430 
00431     db_conf = gw_malloc(sizeof(DBConf));
00432     gw_assert(db_conf != NULL);
00433 
00434     db_conf->sdb = gw_malloc(sizeof(SDBConf));
00435     gw_assert(db_conf->sdb != NULL);
00436 
00437     db_conf->sdb->url = sdb_url;
00438 
00439     pool = dbpool_create(DBPOOL_SDB, db_conf, pool_size);
00440     gw_assert(pool != NULL);
00441 
00442     /*
00443      * XXX should a failing connect throw panic?!
00444      */
00445     if (dbpool_conn_count(pool) == 0)
00446         panic(0,"DLR: SDB: database pool has no connections!");
00447 
00448     return &handles;
00449 }
00450 #else
00451 /*
00452  * Return NULL , so we point dlr-core that we were
00453  * not compiled in.
00454  */
00455 struct dlr_storage *dlr_init_sdb(Cfg* cfg)
00456 {
00457     return NULL;
00458 }
00459 #endif /* HAVE_SDB */
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.