[PATCH] MongoDB DLR support

Roman Shterenzon <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Good day,

I've added support for using MongoDB document database for DLR storage.
I wouldn't call this production grade, but rather tag it as a "works for me" or "experimental".

The code is hosted on github:
https://github.com/romanbsd/kannel-mongodb


Your feedback is appreciated!

--Roman
kannel-mongodb.patch (application/octet-stream, 23.1 KB)
diff --git a/configure.in b/configure.in
index ee6c28e..529ab8b 100644
--- a/configure.in
+++ b/configure.in
@@ -1207,6 +1207,30 @@ fi
   AC_MSG_RESULT(disabled)
 ])
 
+dnl Implement the --with-mongodb option. This will set HAVE_MONGODB in gw-config.h
+dnl accordingly and enable the usage of the libsqlite3 routines.
+
+AC_MSG_CHECKING([whether to compile with MongoDB support])
+AC_ARG_WITH(mongodb,
+[  --with-mongodb          enable MongoDB storage @<:@disabled@:>@], [
+if test "$withval" != yes; then
+    AC_MSG_RESULT(disabled)
+else
+    AC_MSG_RESULT(searching)
+    AC_CHECK_HEADERS(mongo/mongo.h)
+    LIBS="$LIBS -L/usr/local/lib"
+    AC_CHECK_LIB(mongoc, mongo_connect,
+      [LIBS="$LIBS -lmongoc"
+       AC_DEFINE(HAVE_MONGODB)
+       MONGODB="yes"],
+      [AC_MSG_ERROR([Unable to find MongoDB client libraries])]
+    )
+fi
+],[
+  AC_MSG_RESULT(disabled)
+])
+
+
 dnl Checking for FreeTDS Ct-Lib support
 AC_MSG_CHECKING([whether to compile with FreeTDS Ct-Lib support])
 AC_ARG_WITH(mssql,
diff --git a/doc/examples/dlr-mongodb.conf b/doc/examples/dlr-mongodb.conf
new file mode 100644
index 0000000..91a9962
--- /dev/null
+++ b/doc/examples/dlr-mongodb.conf
@@ -0,0 +1,29 @@
+#
+# DLR with MongoDB support configuration
+#
+# Example defining a MongoDB database connection resource and 
+# the required table and field values.
+#
+
+group = mongodb-connection
+id = mydlr
+host = 127.0.0.1
+#username = foo
+#password = bar
+database = kannel
+# max count of connections that will be opened for dbpool
+# default is 1
+#max-connections = 2
+
+group = dlr-db
+id = mydlr
+table = dlr
+field-smsc = smsc
+field-timestamp = ts
+field-destination = destination
+field-source = source
+field-service = service
+field-url = url
+field-mask = mask
+field-status = status
+field-boxc-id = boxc
diff --git a/gw-config.h.in b/gw-config.h.in
index b3bf950..4a635fd 100644
--- a/gw-config.h.in
+++ b/gw-config.h.in
@@ -227,6 +227,9 @@
 /* Define if you have and want to use the SQLite3 database library (-lsqlite3) */
 #undef HAVE_SQLITE3
 
+/* Define if you have and want to use the MongoDB database library (-lmongoc) */
+#undef HAVE_MONGODB
+
 /* Define version of used libSDB */
 #undef LIBSDB_VERSION
 
diff --git a/gw/dlr.c b/gw/dlr.c
index 2c99a08..60b1132 100644
--- a/gw/dlr.c
+++ b/gw/dlr.c
@@ -262,6 +262,8 @@ void dlr_init(Cfg* cfg)
         handles = dlr_init_mssql(cfg);
     } else if (octstr_compare(dlr_type, octstr_imm("sqlite3")) == 0) {
         handles = dlr_init_sqlite3(cfg);
+    } else if (octstr_compare(dlr_type, octstr_imm("mongodb")) == 0) {
+        handles = dlr_init_mongodb(cfg);
     }
 
     /*
diff --git a/gw/dlr_mongodb.c b/gw/dlr_mongodb.c
new file mode 100644
index 0000000..bb42fff
--- /dev/null
+++ b/gw/dlr_mongodb.c
@@ -0,0 +1,411 @@
+/* Copyright (c) 2011 by Roman Shterenzon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "gwlib/gwlib.h"
+#include "gwlib/dbpool.h"
+#include "dlr_p.h"
+
+/*
+ * dlr_mongodb.c - Implementation of handling delivery reports (DLRs)
+ *                 for MongoDB
+ *
+ * Requires MongoDB C driver:
+ * http://github.com/mongodb/mongo-c-driver
+ */
+#ifdef HAVE_MONGODB
+#include <mongo/mongo.h>
+
+/*
+ * Our connection pool to mongodb.
+ */
+static DBPool *pool = NULL;
+
+/*
+ * Document fields, which we are using.
+ */
+static struct dlr_db_fields *fields = NULL;
+
+/* Database and table */
+static char *mongodb_database = NULL;
+static char *mongodb_table = NULL;
+
+/* Namespace which will be used on MongoDB */
+static char *mongodb_namespace = NULL;
+
+static void mongodb_error(const char *method, mongo_exception_type type)
+{
+    error(0, "MongoDB: %s: %s", method, type == MONGO_EXCEPT_NETWORK ? "network error" : "error in find");
+}
+
+static void dlr_mongodb_shutdown()
+{
+    dbpool_destroy(pool);
+    dlr_db_fields_destroy(fields);
+    mongodb_database = NULL;
+    mongodb_table = NULL;
+    if (mongodb_namespace) {
+        gw_free(mongodb_namespace);
+        mongodb_namespace = NULL;
+    }
+}
+
+/* Add a new DLR entry to MongoDB */
+static void dlr_mongodb_add(struct dlr_entry *entry)
+{
+    DBPoolConn *pconn;
+    bson b;
+    bson_buffer buf;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        dlr_entry_destroy(entry);
+        return;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    bson_buffer_init(&buf);
+    bson_append_new_oid(&buf, "_id");
+
+    bson_append_string(&buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(entry->smsc));
+    bson_append_string(&buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(entry->timestamp));
+    bson_append_string(&buf, octstr_get_cstr(fields->field_src), octstr_get_cstr(entry->source));
+    bson_append_string(&buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(entry->destination));
+    bson_append_string(&buf, octstr_get_cstr(fields->field_serv), octstr_get_cstr(entry->service));
+    bson_append_string(&buf, octstr_get_cstr(fields->field_url), octstr_get_cstr(entry->url));
+    bson_append_int(&buf, octstr_get_cstr(fields->field_mask), entry->mask);
+    bson_append_string(&buf, octstr_get_cstr(fields->field_boxc), octstr_get_cstr(entry->boxc_id));
+    bson_append_int(&buf, octstr_get_cstr(fields->field_status), 0);
+
+    bson_from_buffer(&b, &buf);
+
+    /* TODO: namespace support */
+    MONGO_TRY {
+        mongo_insert(conn, mongodb_namespace, &b);
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_insert", conn->exception.type);
+    }
+
+    dbpool_conn_produce(pconn);
+
+    bson_destroy(&b);
+    dlr_entry_destroy(entry);
+}
+
+static struct dlr_entry* dlr_mongodb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
+{
+    DBPoolConn *pconn;
+    bson cond, obj;
+    bson_buffer cond_buf;
+    bson_iterator it;
+    struct dlr_entry *res = NULL;
+    bson_bool_t found = 0;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        return NULL;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    bson_buffer_init(&cond_buf);
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc));
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
+
+    if (dst) {
+        bson_append_string(&cond_buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(dst));
+    }
+
+    bson_from_buffer(&cond, &cond_buf);
+
+    memset(&obj, 0, sizeof(bson));
+    MONGO_TRY {
+        found = mongo_find_one(conn, mongodb_namespace, &cond, NULL, &obj);
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_get", conn->exception.type);
+        found = 0;
+    }
+
+    if (found) {
+        res = dlr_entry_create();
+        gw_assert(res != NULL);
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_mask));
+        res->mask = bson_iterator_int(&it);
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_serv));
+        res->service = octstr_create(bson_iterator_string(&it));
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_url));
+        res->url = octstr_create(bson_iterator_string(&it));
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_src));
+        res->source = octstr_create(bson_iterator_string(&it));
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_dst));
+        res->destination = octstr_create(bson_iterator_string(&it));
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_boxc));
+        res->boxc_id = octstr_create(bson_iterator_string(&it));
+
+        bson_find(&it, &obj, octstr_get_cstr(fields->field_smsc));
+        res->smsc = octstr_create(bson_iterator_string(&it));
+    }
+
+    dbpool_conn_produce(pconn);
+    bson_destroy(&cond);
+    bson_destroy(&obj);
+
+    return res;
+}
+
+/* Update DLR */
+static void dlr_mongodb_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status)
+{
+    DBPoolConn *pconn;
+    bson cond, op;
+    bson_buffer cond_buf, op_buf;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        return;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    bson_buffer_init(&cond_buf);
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc));
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
+
+    if (dst) {
+        bson_append_string(&cond_buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(dst));
+    }
+
+    bson_from_buffer(&cond, &cond_buf);
+
+    bson_buffer_init(&op_buf);
+    {
+        bson_buffer *sub = bson_append_start_object(&op_buf, "$set");
+        bson_append_int(sub, octstr_get_cstr(fields->field_status), status);
+        bson_append_finish_object(sub);
+    }
+    bson_from_buffer(&op, &op_buf);
+
+    MONGO_TRY {
+        mongo_update(conn, mongodb_namespace, &cond, &op, 0);
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_update", conn->exception.type);
+    }
+
+    dbpool_conn_produce(pconn);
+    bson_destroy(&cond);
+    bson_destroy(&op);
+}
+
+/* Remove DLR */
+static void dlr_mongodb_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
+{
+    DBPoolConn *pconn;
+    bson cond;
+    bson_buffer cond_buf;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        return;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    bson_buffer_init(&cond_buf);
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc));
+    bson_append_string(&cond_buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts));
+
+    if (dst) {
+        bson_append_string(&cond_buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(dst));
+    }
+
+    bson_from_buffer(&cond, &cond_buf);
+
+    MONGO_TRY {
+        mongo_remove(conn, mongodb_namespace, &cond);
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_remove", conn->exception.type);
+    }
+
+    dbpool_conn_produce(pconn);
+    bson_destroy(&cond);
+}
+
+/* Number of DLRs in our namespace */
+static long dlr_mongodb_messages(void)
+{
+    DBPoolConn *pconn;
+    long count = 0;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        return -1;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    /* TODO: namespace support */
+    MONGO_TRY {
+        count = mongo_count(conn, mongodb_database, mongodb_table, NULL);
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_messages", conn->exception.type);
+    }
+
+    dbpool_conn_produce(pconn);
+    return count;
+}
+
+/* Remove all DLRs from our namespace */
+static void dlr_mongodb_flush(void)
+{
+    DBPoolConn *pconn;
+    bson b;
+    mongo_connection *conn = NULL;
+
+    pconn = dbpool_conn_consume(pool);
+    if (pconn == NULL) {
+        return;
+    }
+    conn = (mongo_connection*)pconn->conn;
+
+    MONGO_TRY {
+        mongo_remove(conn, mongodb_namespace, bson_empty(&b));
+    } MONGO_CATCH {
+        mongodb_error("dlr_mongodb_flush", conn->exception.type);
+    }
+    dbpool_conn_produce(pconn);
+}
+
+static struct dlr_storage handles = {
+    .type = "mongodb",
+    .dlr_add = dlr_mongodb_add,
+    .dlr_get = dlr_mongodb_get,
+    .dlr_update = dlr_mongodb_update,
+    .dlr_remove = dlr_mongodb_remove,
+    .dlr_shutdown = dlr_mongodb_shutdown,
+    .dlr_messages = dlr_mongodb_messages,
+    .dlr_flush = dlr_mongodb_flush
+};
+
+struct dlr_storage *dlr_init_mongodb(Cfg *cfg)
+{
+    CfgGroup *grp;
+    List *grplist;
+    Octstr *mongodb_host, *mongodb_user, *mongodb_pass, *mongodb_db, *mongodb_id;
+    long pool_size;
+    long mongodb_port = 27017;
+    DBConf *db_conf = NULL;
+    int found;
+
+    if ((grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))) == NULL) {
+        panic(0, "DLR: MongoDB: group 'dlr-db' is not specified!");
+    }
+
+    if (!(mongodb_id = cfg_get(grp, octstr_imm("id")))) {
+        panic(0, "DLR: MongoDB: directive 'id' is not specified!");
+    }
+
+    /* initialize database fields */
+    fields = dlr_db_fields_create(grp);
+    gw_assert(fields != NULL);
+
+    grplist = cfg_get_multi_group(cfg, octstr_imm("mongodb-connection"));
+    found = 0;
+    while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
+        Octstr *p = cfg_get(grp, octstr_imm("id"));
+        if (p != NULL && octstr_compare(p, mongodb_id) == 0) {
+            found = 1;
+        }
+        if (p != NULL) {
+            octstr_destroy(p);
+        }
+        if (found == 1) {
+            break;
+        }
+    }
+    gwlist_destroy(grplist, NULL);
+
+    if (found == 0) {
+        panic(0, "DLR: MongoDB: connection settings for id '%s' are not specified!",
+              octstr_get_cstr(mongodb_id));
+    }
+
+    if (!(mongodb_host = cfg_get(grp, octstr_imm("host")))) {
+   	    panic(0, "DLR: MongoDB: directive 'host' is not specified!");
+    }
+
+    if (!(mongodb_db = cfg_get(grp, octstr_imm("database")))) {
+   	    panic(0, "DLR: MongoDB: directive 'database' is not specified!");
+    }
+    /* Keep a global reference to the database and table */
+    mongodb_database = octstr_get_cstr(mongodb_db);
+    mongodb_table = octstr_get_cstr(fields->table);
+    mongodb_namespace = (char *)gw_malloc(strlen(mongodb_database) + strlen(mongodb_table) + 2); /* . and \0 */
+    sprintf(mongodb_namespace, "%s.%s", mongodb_database, mongodb_table);
+
+    mongodb_user = cfg_get(grp, octstr_imm("username"));
+    mongodb_pass = cfg_get(grp, octstr_imm("password"));
+   	    
+    cfg_get_integer(&mongodb_port, grp, octstr_imm("port"));  /* optional */
+    
+    if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1) {
+        pool_size = 1;
+    }
+
+    /* ok we are ready to create dbpool */
+    db_conf = gw_malloc(sizeof(*db_conf));
+    gw_assert(db_conf != NULL);
+
+    db_conf->mongodb = gw_malloc(sizeof(MongoDBConf));
+    gw_assert(db_conf->mongodb != NULL);
+
+    db_conf->mongodb->host = mongodb_host;
+    db_conf->mongodb->port = mongodb_port;
+    db_conf->mongodb->username = mongodb_user;
+    db_conf->mongodb->password = mongodb_pass;
+    db_conf->mongodb->database = mongodb_db;
+
+    pool = dbpool_create(DBPOOL_MONGODB, db_conf, pool_size);
+    gw_assert(pool != NULL);
+
+    if (dbpool_conn_count(pool) == 0) {
+        panic(0, "DLR: MongoDB: Could not establish connection(s).");
+    }
+
+    octstr_destroy(mongodb_id);
+
+    return &handles;
+}
+#else
+/*
+ * Return NULL , so we point dlr-core that we were
+ * not compiled in.
+ */
+struct dlr_storage *dlr_init_mongodb(Cfg *cfg)
+{
+	return NULL;
+}
+#endif
diff --git a/gw/dlr_p.h b/gw/dlr_p.h
index 63d273c..56603f4 100644
--- a/gw/dlr_p.h
+++ b/gw/dlr_p.h
@@ -172,6 +172,7 @@ struct dlr_storage *dlr_init_oracle(Cfg *cfg);
 struct dlr_storage *dlr_init_pgsql(Cfg *cfg);
 struct dlr_storage *dlr_init_mssql(Cfg *cfg);
 struct dlr_storage *dlr_init_sqlite3(Cfg *cfg);
+struct dlr_storage *dlr_init_mongodb(Cfg *cfg);
 
 
 #endif /* DLR_P_H */
diff --git a/gwlib/cfg.def b/gwlib/cfg.def
index f0a477f..0baca5d 100644
--- a/gwlib/cfg.def
+++ b/gwlib/cfg.def
@@ -606,6 +606,15 @@ MULTI_GROUP(sqlite3-connection,
     OCTSTR(lock-timeout)
 )
 
+MULTI_GROUP(mongodb-connection,
+    OCTSTR(id)
+    OCTSTR(host)
+    OCTSTR(port)
+    OCTSTR(username)
+    OCTSTR(password)
+    OCTSTR(database)
+    OCTSTR(max-connections)
+)
  
 SINGLE_GROUP(dlr-db,
     OCTSTR(id)
@@ -647,7 +656,3 @@ MULTI_GROUP(smpp-tlv,
 #undef OCTSTR
 #undef SINGLE_GROUP
 #undef MULTI_GROUP
-
-
-
-
diff --git a/gwlib/dbpool.c b/gwlib/dbpool.c
index b191280..6d93130 100644
--- a/gwlib/dbpool.c
+++ b/gwlib/dbpool.c
@@ -80,6 +80,7 @@
 #include "dbpool_sdb.c"
 #include "dbpool_pgsql.c"
 #include "dbpool_mssql.c"
+#include "dbpool_mongodb.c"
 
 
 static void dbpool_conn_destroy(DBPoolConn *conn)
@@ -149,6 +150,11 @@ DBPool *dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connectio
            p->db_ops = &pgsql_ops;
            break;
 #endif
+#ifdef HAVE_MONGODB
+       case DBPOOL_MONGODB:
+           p->db_ops = &mongodb_ops;
+           break;
+#endif
         default:
             panic(0, "Unknown dbpool type defined.");
     }
diff --git a/gwlib/dbpool.h b/gwlib/dbpool.h
index ad0914c..c57e437 100644
--- a/gwlib/dbpool.h
+++ b/gwlib/dbpool.h
@@ -67,14 +67,14 @@
 #if defined(HAVE_MYSQL) || defined(HAVE_SDB) || \
     defined(HAVE_ORACLE) || defined(HAVE_SQLITE) || \
     defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) || \
-    defined(HAVE_MSSQL)
+    defined(HAVE_MSSQL) || defined(HAVE_MONGODB)
 #define HAVE_DBPOOL 1
 #endif
 
 /* supported databases for connection pools */
 enum db_type {
     DBPOOL_MYSQL, DBPOOL_SDB, DBPOOL_ORACLE, DBPOOL_SQLITE, DBPOOL_PGSQL,
-    DBPOOL_SQLITE3, DBPOOL_MSSQL
+    DBPOOL_SQLITE3, DBPOOL_MSSQL, DBPOOL_MONGODB
 };
 
 
@@ -143,6 +143,14 @@ typedef struct {
     Octstr *tty;        /* yet not used */
 } PgSQLConf;
 
+typedef struct {
+    Octstr *host;
+    long port;
+    Octstr *username;
+    Octstr *password;
+    Octstr *database;
+} MongoDBConf;
+
 typedef union {
     MSSQLConf *mssql;
     MySQLConf *mysql;
@@ -151,6 +159,7 @@ typedef union {
     SQLiteConf *sqlite;
     SQLite3Conf *sqlite3;
     PgSQLConf *pgsql;
+    MongoDBConf *mongodb;
 } DBConf;
 
 /*
diff --git a/gwlib/dbpool_mongodb.c b/gwlib/dbpool_mongodb.c
new file mode 100644
index 0000000..14a51f1
--- /dev/null
+++ b/gwlib/dbpool_mongodb.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2011 by Roman Shterenzon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * dbpool_mongodb.c - implement MongoDB operations for generic database connection pool
+ *
+ */
+
+#ifdef HAVE_MONGODB
+#include <mongo/mongo.h>
+
+/* Our pointer to the configuration */
+static MongoDBConf *mongo_conf = NULL;
+
+static void *mongodb_open_conn(const DBConf *db_conf)
+{
+    MongoDBConf *conf = db_conf->mongodb;
+    mongo_connection *conn; /* ptr */
+    mongo_connection_options opts[1];
+    mongo_conn_return status;
+    mongo_conf = conf;
+/*
+    octstr_get_cstr(conf->username),
+    octstr_get_cstr(conf->password),
+    octstr_get_cstr(conf->database),
+*/
+    conn = gw_malloc(sizeof(mongo_connection));
+    gw_assert(conn != NULL);
+
+    strcpy(opts->host, octstr_get_cstr(conf->host));
+    opts->port = conf->port;
+    info(0, "MongoDB: connecting to %s:%u", opts->host, opts->port);
+
+    status = mongo_connect(conn, opts);
+
+    switch (status) {
+    case mongo_conn_success:
+        info(0, "MongoDB: connected");
+        break;
+    case mongo_conn_bad_arg:
+        error(0, "MongoDB: bad arguments");
+        goto failed;
+    case mongo_conn_no_socket:
+        error(0, "MongoDB: no socket");
+        goto failed;
+    case mongo_conn_fail:
+        error(0, "MongoDB: connection failed");
+        goto failed;
+    case mongo_conn_not_master:
+        error(0, "MongoDB: not master");
+        goto failed;
+    }
+
+/*
+    if (conf->username && conf->password &&
+        !mongo_cmd_authenticate(conn, octstr_get_cstr(conf->database), octstr_get_cstr(conf->username), octstr_get_cstr(conf->password))) {
+        error(0, "MongoDB: authentication failed");
+        goto failed;
+    }
+*/
+
+    return conn;
+
+failed:
+    if (conn != NULL) {
+        mongo_destroy(conn);
+        gw_free(conn);
+    }
+    return NULL;
+}
+
+/* Close connection and deallocate */
+static void mongodb_close_conn(void *conn)
+{
+    if (conn == NULL) {
+        return;
+    }
+    mongo_destroy((mongo_connection*)conn);
+    gw_free(conn);
+}
+
+static bson_bool_t mongodb_cmd_ping(mongo_connection *conn, const char *db)
+{
+    bson out;
+    bson_bool_t res;
+    bson_iterator it;
+
+    memset(&out, 0, sizeof(bson));
+    res = mongo_simple_int_command(conn, db, "ping", 1, &out);
+    if (res) {
+        if (bson_find(&it, &out, "ok") == bson_eoo) {
+            res = 0;
+        } else {
+            res = bson_iterator_bool(&it);
+        }
+    }
+
+    bson_destroy(&out);
+    return res;
+}
+
+/* Check if the connection is alive and usable */
+static int mongodb_check_conn(void *mconn)
+{
+    int res = 0;
+    mongo_connection *conn = (mongo_connection*)mconn;
+
+    if (conn == NULL || mongo_conf == NULL) {
+        return -1;
+    }
+
+    if (!conn->connected) {
+        return -1;
+    }
+
+    MONGO_TRY {
+        if (!mongodb_cmd_ping(conn, octstr_get_cstr(mongo_conf->database))) {
+            res = -1;
+        }
+    } MONGO_CATCH {
+        error(0, "MongoDB: mongodb_check_conn failed!");
+        res = -1;
+    }
+
+    return res;
+}
+
+/* Why is it needed? */
+static int mongodb_select(void *conn, const Octstr *sql, List *binds, List **res)
+{
+    gw_assert(0);
+    return 0;
+}
+
+/* Why is it needed? */
+static int mongodb_update(void *conn, const Octstr *stmt, List *binds)
+{
+    gw_assert(0);
+    return 0;
+}
+
+/* Free memory allocated by MongoDB configuration */
+static void mongodb_conf_destroy(DBConf *db_conf)
+{
+    MongoDBConf *conf = db_conf->mongodb;
+
+    octstr_destroy(conf->host);
+    octstr_destroy(conf->username);
+    octstr_destroy(conf->password);
+    octstr_destroy(conf->database);
+
+    gw_free(conf);
+    gw_free(db_conf);
+    mongo_conf = NULL;
+}
+
+static struct db_ops mongodb_ops = {
+    .open = mongodb_open_conn,
+    .close = mongodb_close_conn,
+    .check = mongodb_check_conn,
+    .conf_destroy = mongodb_conf_destroy,
+    .update = mongodb_update,
+    .select = mongodb_select
+};
+
+#endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.