[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