Переглянути джерело

ndb_mongodb: new module offering a non-db connector to MongoDB from config file

Daniel-Constantin Mierla 11 роки тому
батько
коміт
97b8731504

+ 25 - 0
modules/ndb_mongodb/Makefile

@@ -0,0 +1,25 @@
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=ndb_mongodb.so
+
+ifeq ($(CROSS_COMPILE),)
+MONGODBC_BUILDER=$(shell \
+	if pkg-config --exists libmongoc-1.0; then \
+		echo 'pkg-config libmongoc-1.0'; \
+	fi)
+endif
+
+ifneq ($(MONGODBC_BUILDER),)
+	DEFS += $(shell $(MONGODBC_BUILDER) --cflags)
+	LIBS += $(shell $(MONGODBC_BUILDER) --libs)
+else
+	DEFS += -I$(LOCALBASE)/include
+	LIBS= -L$(LOCALBASE)/lib -lmongoc
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 251 - 0
modules/ndb_mongodb/README

@@ -0,0 +1,251 @@
+NDB_MONGODB Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2014 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. server (str)
+
+        4. Functions
+
+              4.1. mongodb_cmd(srvname, dbname, cname, command, replyid)
+              4.2. mongodb_cmd(srvname, dbname, cname, command, replyid)
+              4.3. mongodb_find(srvname, dbname, cname, command, replyid)
+              4.4. mongodb_next(replyid)
+              4.5. mongodb_free(replyid)
+
+   List of Examples
+
+   1.1. Set server parameter
+   1.2. mongodb_cmd usage
+   1.3. mongodb_cmd_simple usage
+   1.4. mongodb_find usage
+   1.5. mongodb_next usage
+   1.6. mongodb_free usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. server (str)
+
+   4. Functions
+
+        4.1. mongodb_cmd(srvname, dbname, cname, command, replyid)
+        4.2. mongodb_cmd(srvname, dbname, cname, command, replyid)
+        4.3. mongodb_find(srvname, dbname, cname, command, replyid)
+        4.4. mongodb_next(replyid)
+        4.5. mongodb_free(replyid)
+
+1. Overview
+
+   This module provides a non-db connector to interact with MongoDB NoSQL
+   server from configuration file. You can read more about MongoDB at
+   http://www.mongodb.org.
+
+   It can connect to many MongoDB servers and store the results in
+   different containers.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * mongo-c-driver - available at
+       https://github.com/mongodb/mongo-c-driver
+
+3. Parameters
+
+   3.1. server (str)
+
+3.1. server (str)
+
+   Specify the details to connect to REDIS server. It takes a list of
+   attribute=value separated by semicolon, the attributes can be name and
+   uri. Name is a generic identifier to be used with module functions. The
+   uri parameter must be a valid MongoDB database connection string.
+
+   You can set this parameter many times, in case you want to connect to
+   many MongoDB servers, just give different attributes and use the
+   specific server name when querying the MongoDB instance.
+
+   Default value is NULL.
+
+   Example 1.1. Set server parameter
+...
+modparam("ndb_mongodb", "server", "name=mgs1;uri='mongodb://localhost/kamailio'"
+)
+modparam("ndb_mongodb", "server", "name=mgs2;uri='mongodb://127.0.0.2/kamailio'"
+)
+...
+
+4. Functions
+
+   4.1. mongodb_cmd(srvname, dbname, cname, command, replyid)
+   4.2. mongodb_cmd(srvname, dbname, cname, command, replyid)
+   4.3. mongodb_find(srvname, dbname, cname, command, replyid)
+   4.4. mongodb_next(replyid)
+   4.5. mongodb_free(replyid)
+
+4.1.  mongodb_cmd(srvname, dbname, cname, command, replyid)
+
+   Send a valid command to MongoDB server identified by srvname. The reply
+   will be stored in a local container identified by replyid. All the
+   parameters can be strings with pseudo-variables that are evaluated at
+   runtime.
+
+   The reply can be accessed via pseudo-variable $mongodb(key). The key
+   can be: type - type of the reply; value - the value in JSON format
+   returned by MongoDB server; info - in case of error from MongoDB, it
+   will contain an info message.
+
+   The result can contain many documents, see mongodb_next() function for
+   more details.
+
+   Meaning of the parameters:
+     * srvname - MongoDB server name as given via 'server' parameter.
+     * dbname - MongoDB database name.
+     * cname - MongodDB collection (table) name.
+     * command - valid MongoDB command given as JSON string.
+     * replyid - the name of the container to store the response.
+
+   The function can be used from ANY_ROUTE.
+
+   Example 1.2. mongodb_cmd usage
+...
+if(mongodb_cmd("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "mgr1"))
+ {
+        xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+
+4.2.  mongodb_cmd(srvname, dbname, cname, command, replyid)
+
+   Send a valid command to MongoDB server identified by srvname. The reply
+   will be stored in a local container identified by replyid. All the
+   parameters can be strings with pseudo-variables that are evaluated at
+   runtime.
+
+   The reply can be accessed via pseudo-variable $mongodb(key). The key
+   can be: type - type of the reply; value - the value in JSON format
+   returned by MongoDB server; info - in case of error from MongoDB, it
+   will contain an info message.
+
+   This function should be used when the response has only one document.
+
+   See mongodb_cmd() for the meaning of the parameters.
+
+   The function can be used from ANY_ROUTE.
+
+   Example 1.3. mongodb_cmd_simple usage
+...
+if(mongodb_cmd_simple("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "
+mgr1")) {
+        xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+
+4.3.  mongodb_find(srvname, dbname, cname, command, replyid)
+
+   Send a find command to MongoDB server identified by srvname. The reply
+   will be stored in a local container identified by replyid. All the
+   parameters can be strings with pseudo-variables that are evaluated at
+   runtime.
+
+   The reply can be accessed via pseudo-variable $mongodb(key). The key
+   can be: type - type of the reply; value - the value in JSON format
+   returned by MongoDB server; info - in case of error from MongoDB, it
+   will contain an info message.
+
+   This function is useful for querying collections and accessing the
+   results.
+
+   See mongodb_cmd() for the meaning of the parameters, with the remark
+   that command has to be a valid filter JSON document, like for find()
+   command in mongoc command line client tool.
+
+   The function can be used from ANY_ROUTE.
+
+   Example 1.4. mongodb_find usage
+...
+if(mongodb_find("mgs1", "kamailio", "acc", "{ \"src_user\" : \"111\" }", "mgr1")
+) {
+        xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+
+4.4.  mongodb_next(replyid)
+
+   Moves to next document in a MongoDB reply. This function can be used
+   after a succesful mongodb_cmd() or mongodb_find(). It returns true if
+   there is a shift to document. The current document becomes available
+   via $mongodb(key) variable.
+
+   Example 1.5. mongodb_next usage
+...
+if(mongodb_find("mgs1", "kamailio", "acc", "{ \"src_user\" : \"111\" }", "mgr1")
+) {
+    xlog("first response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+    while(mongodb_next("mgr1") ){
+        xlog("next response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+    }
+}
+mongodb_free("mgr1");
+...
+
+4.5.  mongodb_free(replyid)
+
+   Frees data in a previous reply from memory. After this function call,
+   accessing to a freed replyid returns null value.
+
+   It is not really necessary to free a reply to use it again in a new
+   mongodb_cmd function, being automatically freed on next command
+   execution, but for freeing used resources (e.g., memory), it is
+   recommended to do it.
+
+   Example 1.6. mongodb_free usage
+...
+if(mongodb_cmd_simple("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "
+mgr1")) {
+        xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+mongodb_free("mgr1");
+...

+ 4 - 0
modules/ndb_mongodb/doc/Makefile

@@ -0,0 +1,4 @@
+docs = ndb_mongodb.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/ndb_mongodb/doc/ndb_mongodb.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>NDB_MONGODB Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2014</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="ndb_mongodb_admin.xml"/>
+    
+    
+</book>

+ 289 - 0
modules/ndb_mongodb/doc/ndb_mongodb_admin.xml

@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides a non-db connector to interact with MongoDB NoSQL
+		server from configuration file. You can read more about MongoDB at
+		<ulink url="http://www.mongodb.org">http://www.mongodb.org</ulink>.
+	</para>
+	<para>
+		It can connect to many MongoDB servers and store the results in different
+		containers.
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>mongo-c-driver</emphasis> - available at
+				<ulink url="https://github.com/mongodb/mongo-c-driver">https://github.com/mongodb/mongo-c-driver</ulink>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Parameters</title>
+	<section id="ndb_redis.p.server">
+		<title><varname>server</varname> (str)</title>
+		<para>
+			Specify the details to connect to REDIS server. It takes a list of
+			attribute=value separated by semicolon, the attributes can be
+			name and uri. Name is a generic identifier to be used
+			with module functions. The uri parameter must be a valid
+			MongoDB database connection string.
+		</para>
+		<para>
+			You can set this parameter many times, in case you want to connect to
+			many MongoDB servers, just give different attributes and use the specific
+			server name when querying the MongoDB instance.
+		</para>
+		<para>
+		<emphasis>
+			Default value is NULL.
+		</emphasis>
+		</para>
+		<example>
+			<title>Set <varname>server</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("ndb_mongodb", "server", "name=mgs1;uri='mongodb://localhost/kamailio'")
+modparam("ndb_mongodb", "server", "name=mgs2;uri='mongodb://127.0.0.2/kamailio'")
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section id="ndb_mongodb.f.mongodb_cmd">
+	    <title>
+		<function moreinfo="none">mongodb_cmd(srvname, dbname, cname, command, replyid)</function>
+	    </title>
+	    <para>
+			Send a valid command to MongoDB server identified by srvname. The reply will
+			be stored in a local container identified by replyid. All the
+			parameters can be strings with pseudo-variables that are evaluated
+			at runtime.
+		</para>
+		<para>
+			The reply can be accessed via pseudo-variable $mongodb(key). The key
+			can be: type - type of the reply; value - the value in JSON format
+			returned by MongoDB server; info - in case of error from MongoDB, it will
+			contain an info message.
+		</para>
+		<para>
+			The result can contain many documents, see mongodb_next() function for
+			more details.
+		</para>
+		<para>
+			Meaning of the parameters:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>srvname</emphasis> - MongoDB server name as given via
+				'server' parameter.
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>dbname</emphasis> - MongoDB database name.
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>cname</emphasis> - MongodDB collection (table) name.
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>command</emphasis> - valid MongoDB command given
+				as JSON string.
+			</para>
+			</listitem>
+			<listitem>
+			<para>
+				<emphasis>replyid</emphasis> - the name of the container to
+				store the response.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+		<para>
+			The function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>mongodb_cmd</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(mongodb_cmd("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "mgr1")) {
+	xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section id="ndb_mongodb.f.mongodb_cmd_simple">
+	    <title>
+		<function moreinfo="none">mongodb_cmd(srvname, dbname, cname, command, replyid)</function>
+	    </title>
+	    <para>
+			Send a valid command to MongoDB server identified by srvname. The reply will
+			be stored in a local container identified by replyid. All the
+			parameters can be strings with pseudo-variables that are evaluated
+			at runtime.
+		</para>
+		<para>
+			The reply can be accessed via pseudo-variable $mongodb(key). The key
+			can be: type - type of the reply; value - the value in JSON format
+			returned by MongoDB server; info - in case of error from MongoDB, it will
+			contain an info message.
+		</para>
+		<para>
+			This function should be used when the response has only one document.
+		</para>
+		<para>
+			See mongodb_cmd() for the meaning of the parameters.
+		</para>
+		<para>
+			The function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>mongodb_cmd_simple</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(mongodb_cmd_simple("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "mgr1")) {
+	xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section id="ndb_mongodb.f.mongodb_find">
+	    <title>
+		<function moreinfo="none">mongodb_find(srvname, dbname, cname, command, replyid)</function>
+	    </title>
+	    <para>
+			Send a find command to MongoDB server identified by srvname. The reply will
+			be stored in a local container identified by replyid. All the
+			parameters can be strings with pseudo-variables that are evaluated
+			at runtime.
+		</para>
+		<para>
+			The reply can be accessed via pseudo-variable $mongodb(key). The key
+			can be: type - type of the reply; value - the value in JSON format
+			returned by MongoDB server; info - in case of error from MongoDB, it will
+			contain an info message.
+		</para>
+		<para>
+			This function is useful for querying collections and accessing the results.
+		</para>
+		<para>
+			See mongodb_cmd() for the meaning of the parameters, with the remark that
+			command has to be a valid filter JSON document, like for find() command
+			in mongoc command line client tool.
+		</para>
+		<para>
+			The function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>mongodb_find</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(mongodb_find("mgs1", "kamailio", "acc", "{ \"src_user\" : \"111\" }", "mgr1")) {
+	xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section id="ndb_mongodb.f.mongodb_next">
+	<title>
+		<function moreinfo="none">mongodb_next(replyid)</function>
+	</title>
+	<para>
+		Moves to next document in a MongoDB reply. This function can be used
+		after a succesful mongodb_cmd() or mongodb_find(). It returns true if
+		there is a shift to document. The current document becomes available
+		via $mongodb(key) variable.
+	</para>
+	<example>
+		<title><function>mongodb_next</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(mongodb_find("mgs1", "kamailio", "acc", "{ \"src_user\" : \"111\" }", "mgr1")) {
+    xlog("first response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+    while(mongodb_next("mgr1") ){
+        xlog("next response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+    }
+}
+mongodb_free("mgr1");
+...
+		</programlisting>
+	</example>
+	</section>
+
+	<section id="ndb_mongodb.f.mongodb_free">
+	<title>
+		<function moreinfo="none">mongodb_free(replyid)</function>
+	</title>
+	<para>
+		Frees data in a previous reply from memory.
+		After this function call, accessing to a freed replyid returns null value.
+	</para>
+	<para>
+		It is not really necessary to free a reply to use it again in a new mongodb_cmd
+		function, being automatically freed on next command execution, but for freeing
+		used resources (e.g., memory), it is recommended to do it.
+	</para>
+	<example>
+		<title><function>mongodb_free</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(mongodb_cmd_simple("mgs1", "kamailio", "acc", "{ \"collStats\": \"acc\" }", "mgr1")) {
+	xlog("response from mongodb is [[$mongodb(mgr1=>value)]]\n");
+}
+mongodb_free("mgr1");
+...
+		</programlisting>
+	</example>
+	</section>
+	</section>
+</chapter>
+

+ 480 - 0
modules/ndb_mongodb/mongodb_client.c

@@ -0,0 +1,480 @@
+/**
+ * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdarg.h>
+
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../hashes.h"
+#include "../../ut.h"
+
+#include "mongodb_client.h"
+
+static mongodbc_server_t *_mongodbc_srv_list=NULL;
+
+static mongodbc_reply_t *_mongodbc_rpl_list=NULL;
+
+void mongodbc_destroy_reply(mongodbc_reply_t *rpl);
+
+/**
+ *
+ */
+int mongodbc_init(void)
+{
+	mongodbc_server_t *rsrv=NULL;
+
+	if(_mongodbc_srv_list==NULL)
+	{
+		LM_ERR("no mongodb servers defined\n");
+		return -1;
+	}
+
+	for(rsrv=_mongodbc_srv_list; rsrv; rsrv=rsrv->next)
+	{
+		if(rsrv->uri==NULL || rsrv->uri->len<=0) {
+			LM_ERR("no uri for server: %.*s\n",
+					rsrv->sname->len, rsrv->sname->s);
+			return -1;
+		}
+		rsrv->client = mongoc_client_new (rsrv->uri->s);
+		if(rsrv->client==NULL) {
+			LM_ERR("failed to connect to: %.*s (%.*s)\n",
+					rsrv->sname->len, rsrv->sname->s,
+					rsrv->uri->len, rsrv->uri->s);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/**
+ *
+ */
+int mongodbc_destroy(void)
+{
+	mongodbc_reply_t *rpl, *next_rpl;
+
+	mongodbc_server_t *rsrv=NULL;
+	mongodbc_server_t *rsrv1=NULL;
+
+	rpl = _mongodbc_rpl_list;
+	while(rpl != NULL)
+	{
+		next_rpl = rpl->next;
+		mongodbc_destroy_reply(rpl);
+		pkg_free(rpl);
+		rpl = next_rpl;
+	}
+	_mongodbc_rpl_list = NULL;
+
+	if(_mongodbc_srv_list==NULL)
+		return -1;
+	rsrv=_mongodbc_srv_list;
+	while(rsrv!=NULL)
+	{
+		rsrv1 = rsrv;
+		rsrv=rsrv->next;
+		if(rsrv1->client!=NULL)
+			mongoc_client_destroy(rsrv1->client);
+		free_params(rsrv1->attrs);
+		pkg_free(rsrv1);
+	}
+	_mongodbc_srv_list = NULL;
+
+	return 0;
+}
+
+/**
+ *
+ */
+int mongodbc_add_server(char *spec)
+{
+	param_t *pit=NULL;
+	param_hooks_t phooks;
+	mongodbc_server_t *rsrv=NULL;
+	str s;
+
+	s.s = spec;
+	s.len = strlen(spec);
+	if(s.s[s.len-1]==';')
+		s.len--;
+	if (parse_params(&s, CLASS_ANY, &phooks, &pit)<0)
+	{
+		LM_ERR("failed parsing params value\n");
+		goto error;
+	}
+	rsrv = (mongodbc_server_t*)pkg_malloc(sizeof(mongodbc_server_t));
+	if(rsrv==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		goto error;
+	}
+	memset(rsrv, 0, sizeof(mongodbc_server_t));
+	rsrv->attrs = pit;
+	for (pit = rsrv->attrs; pit; pit=pit->next)
+	{
+		if(pit->name.len==4 && strncmp(pit->name.s, "name", 4)==0) {
+			rsrv->sname = &pit->body;
+			rsrv->hname = get_hash1_raw(rsrv->sname->s, rsrv->sname->len);
+		} else if(pit->name.len==3 && strncmp(pit->name.s, "uri", 3)==0) {
+			rsrv->uri = &pit->body;
+			if(rsrv->uri->s[rsrv->uri->len]!='\0') rsrv->uri->s[rsrv->uri->len]='\0';
+		}
+	}
+	if(rsrv->sname==NULL || rsrv->uri==NULL)
+	{
+		LM_ERR("no server name or uri\n");
+		goto error;
+	}
+	LM_DBG("added server[%.*s]=%.*s\n",
+			rsrv->sname->len, rsrv->sname->s,
+			rsrv->uri->len, rsrv->uri->s);
+	rsrv->next = _mongodbc_srv_list;
+	_mongodbc_srv_list = rsrv;
+
+	return 0;
+error:
+	if(pit!=NULL)
+		free_params(pit);
+	if(rsrv!=NULL)
+		pkg_free(rsrv);
+	return -1;
+}
+
+/**
+ *
+ */
+mongodbc_server_t *mongodbc_get_server(str *name)
+{
+	mongodbc_server_t *rsrv=NULL;
+	unsigned int hname;
+
+	hname = get_hash1_raw(name->s, name->len);
+	rsrv=_mongodbc_srv_list;
+	while(rsrv!=NULL)
+	{
+		if(rsrv->hname==hname && rsrv->sname->len==name->len
+				&& strncmp(rsrv->sname->s, name->s, name->len)==0)
+			return rsrv;
+		rsrv=rsrv->next;
+	}
+	return NULL;
+}
+
+/**
+ *
+ */
+int mongodbc_reconnect_server(mongodbc_server_t *rsrv)
+{
+	mongoc_init();
+
+	if(rsrv->client!=NULL)
+		mongoc_client_destroy(rsrv->client);
+
+	rsrv->client = mongoc_client_new (rsrv->uri->s);
+	if(rsrv->client!=NULL) {
+		LM_ERR("failed to connect to: %.*s (%.*s)\n",
+				rsrv->sname->len, rsrv->sname->s,
+				rsrv->uri->len, rsrv->uri->s);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int mongodbc_exec_cmd(str *srv, str *dname, str *cname, str *cmd, str *res, int emode)
+{
+	mongodbc_server_t *rsrv=NULL;
+	mongodbc_reply_t *rpl=NULL;
+	bson_error_t error;
+	bson_t command;
+	bson_t reply;
+	const bson_t *cdoc;
+	char c;
+	int ret;
+
+	if(srv==NULL || cmd==NULL || res==NULL)
+	{
+		LM_ERR("invalid parameters");
+		goto error_exec;
+	}
+	if(srv->len==0 || res->len==0 || cmd->len==0)
+	{
+		LM_ERR("invalid parameters");
+		goto error_exec;
+	}
+	rsrv = mongodbc_get_server(srv);
+	if(rsrv==NULL)
+	{
+		LM_ERR("no mongodb server found: %.*s\n", srv->len, srv->s);
+		goto error_exec;
+	}
+	if(rsrv->client==NULL)
+	{
+		if(mongodbc_reconnect_server(rsrv)<0) {
+			LM_ERR("no mongodb context for server: %.*s\n", srv->len, srv->s);
+			goto error_exec;
+		}
+	}
+	rpl = mongodbc_get_reply(res);
+	if(rpl==NULL)
+	{
+		LM_ERR("no mongodb reply id found: %.*s\n", res->len, res->s);
+		goto error_exec;
+	}
+	mongodbc_destroy_reply(rpl);
+
+	rpl->collection = mongoc_client_get_collection (rsrv->client, dname->s, cname->s);
+
+	LM_DBG("trying to execute: [[%.*s]]\n", cmd->len, cmd->s);
+	c = cmd->s[cmd->len];
+	cmd->s[cmd->len] = '\0';
+	if(!bson_init_from_json(&command, cmd->s, cmd->len, &error)) {
+		cmd->s[cmd->len] = c;
+		LM_ERR("Failed to run command: %s\n", error.message);
+		goto error_exec;
+	}
+	cmd->s[cmd->len] = c;
+	if(emode==0) {
+		ret = mongoc_collection_command_simple (rpl->collection, &command, NULL, &reply, &error);
+		if (!ret) {
+			LM_ERR("Failed to run command: %s\n", error.message);
+			bson_destroy (&command);
+			goto error_exec;
+		}
+		bson_destroy (&command);
+		rpl->jsonrpl.s = bson_as_json (&reply, NULL);
+		rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
+		bson_destroy (&reply);
+	} else {
+		if(emode==1) {
+			rpl->cursor = mongoc_collection_command (rpl->collection,
+					MONGOC_QUERY_NONE,
+					0,
+					0,
+					0,
+					&command,
+					NULL,
+					0);
+		} else {
+			rpl->cursor = mongoc_collection_find (rpl->collection,
+					MONGOC_QUERY_NONE,
+					0,
+					0,
+					0,
+					&command,
+					NULL,
+					NULL);
+		}
+		bson_destroy (&command);
+		if(rpl->cursor==NULL) {
+			LM_ERR("Failed to get cursor: %s\n", error.message);
+			goto error_exec;
+		}
+		if (!mongoc_cursor_next (rpl->cursor, &cdoc)) {
+			if (mongoc_cursor_error (rpl->cursor, &error)) {
+				LM_ERR("Cursor failure: %s\n", error.message);
+			}
+			goto error_exec;
+		}
+		rpl->jsonrpl.s = bson_as_json (cdoc, NULL);
+		rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
+	}
+
+	LM_DBG("command result: [[%s]]\n", (rpl->jsonrpl.s)?rpl->jsonrpl.s:"<null>");
+
+	return 0;
+
+error_exec:
+	return -1;
+
+}
+
+/**
+ *
+ */
+int mongodbc_exec_simple(str *srv, str *dname, str *cname, str *cmd, str *res)
+{
+	return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 0);
+}
+
+/**
+ *
+ */
+int mongodbc_exec(str *srv, str *dname, str *cname, str *cmd, str *res)
+{
+	return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 1);
+}
+
+/**
+ *
+ */
+int mongodbc_find(str *srv, str *dname, str *cname, str *cmd, str *res)
+{
+	return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 2);
+}
+
+/**
+ *
+ */
+mongodbc_reply_t *mongodbc_get_reply(str *name)
+{
+	mongodbc_reply_t *rpl;
+	unsigned int hid;
+
+	hid = get_hash1_raw(name->s, name->len);
+
+	for(rpl=_mongodbc_rpl_list; rpl; rpl=rpl->next) {
+		if(rpl->hname==hid && rpl->rname.len==name->len
+				&& strncmp(rpl->rname.s, name->s, name->len)==0)
+			return rpl;
+	}
+	/* not found - add a new one */
+
+	rpl = (mongodbc_reply_t*)pkg_malloc(sizeof(mongodbc_reply_t));
+	if(rpl==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return NULL;
+	}
+	memset(rpl, 0, sizeof(mongodbc_reply_t));
+	rpl->hname = hid;
+	rpl->rname.s = (char*)pkg_malloc(name->len+1);
+	if(rpl->rname.s==NULL)
+	{
+		LM_ERR("no more pkg.\n");
+		pkg_free(rpl);
+		return NULL;
+	}
+	strncpy(rpl->rname.s, name->s, name->len);
+	rpl->rname.len = name->len;
+	rpl->rname.s[name->len] = '\0';
+	rpl->next = _mongodbc_rpl_list;
+	_mongodbc_rpl_list = rpl;
+	return rpl;
+}
+
+/**
+ *
+ */
+void mongodbc_destroy_reply(mongodbc_reply_t *rpl)
+{
+	if(rpl->jsonrpl.s!=NULL) {
+		bson_free(rpl->jsonrpl.s);
+		rpl->jsonrpl.s = NULL;
+		rpl->jsonrpl.len = 0;
+	}
+	if(rpl->cursor) {
+		mongoc_cursor_destroy (rpl->cursor);
+		rpl->cursor = NULL;
+	}
+	if(rpl->collection) {
+		mongoc_collection_destroy (rpl->collection);
+		rpl->collection = NULL;
+	}
+}
+
+/**
+ *
+ */
+int mongodbc_free_reply(str *name)
+{
+	mongodbc_reply_t *rpl;
+	unsigned int hid;
+
+	if(name==NULL || name->len==0) {
+		LM_ERR("invalid parameters");
+		return -1;
+	}
+
+	hid = get_hash1_raw(name->s, name->len);
+
+	rpl = _mongodbc_rpl_list;
+	while(rpl) {
+		if(rpl->hname==hid && rpl->rname.len==name->len
+				&& strncmp(rpl->rname.s, name->s, name->len)==0) {
+			mongodbc_destroy_reply(rpl);
+			return 0;
+		}
+		rpl = rpl->next;
+	}
+
+	/* reply entry not found. */
+	return -1;
+}
+
+/**
+ *
+ */
+int mongodbc_next_reply(str *name)
+{
+	mongodbc_reply_t *rpl;
+	unsigned int hid;
+	bson_error_t error;
+	const bson_t *cdoc;
+
+	if(name==NULL || name->len==0) {
+		LM_ERR("invalid parameters");
+		return -1;
+	}
+
+	hid = get_hash1_raw(name->s, name->len);
+
+	rpl = _mongodbc_rpl_list;
+	while(rpl) {
+		if(rpl->hname==hid && rpl->rname.len==name->len
+				&& strncmp(rpl->rname.s, name->s, name->len)==0) {
+			break;
+		}
+		rpl = rpl->next;
+	}
+	if(!rpl) {
+		/* reply entry not found. */
+		return -1;
+	}
+	if(rpl->cursor==NULL) {
+		LM_DBG("No active cursor for: %.*s\n", rpl->rname.len, rpl->rname.s);
+		return -2;
+	}
+	if (!mongoc_cursor_next (rpl->cursor, &cdoc)) {
+		if (mongoc_cursor_error (rpl->cursor, &error)) {
+			LM_ERR("Cursor failure: %s\n", error.message);
+		}
+		return -2;
+	}
+	if(rpl->jsonrpl.s) {
+		bson_free(rpl->jsonrpl.s);
+		rpl->jsonrpl.s = NULL;
+		rpl->jsonrpl.len = 0;
+	}
+	rpl->jsonrpl.s = bson_as_json (cdoc, NULL);
+	rpl->jsonrpl.len = (rpl->jsonrpl.s)?strlen(rpl->jsonrpl.s):0;
+	LM_DBG("next cursor result: [[%s]]\n", (rpl->jsonrpl.s)?rpl->jsonrpl.s:"<null>");
+	return 0;
+}

+ 72 - 0
modules/ndb_mongodb/mongodb_client.h

@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _MONGODB_CLIENT_H_
+#define _MONGODB_CLIENT_H_
+
+#include <mongoc.h>
+#include <bson.h>
+
+#include "../../str.h"
+#include "../../parser/parse_param.h"
+#include "../../mod_fix.h"
+
+int mongodbc_init(void);
+int mongodbc_destroy(void);
+int mongodbc_add_server(char *spec);
+int mongodbc_exec_simple(str *srv, str *dname, str *cname, str *cmd, str *res);
+int mongodbc_exec(str *srv, str *dname, str *cname, str *cmd, str *res);
+int mongodbc_find(str *srv, str *dname, str *cname, str *cmd, str *res);
+
+typedef struct mongodbc_server {
+	str *sname;
+	str *uri;
+	unsigned int hname;
+	param_t *attrs;
+	mongoc_client_t *client;
+	struct mongodbc_server *next;
+} mongodbc_server_t;
+
+typedef struct mongodbc_reply {
+	str rname;
+	unsigned int hname;
+	mongoc_collection_t *collection;
+	mongoc_cursor_t *cursor;
+	str jsonrpl;
+	struct mongodbc_reply *next;
+} mongodbc_reply_t;
+
+typedef struct mongodbc_pv {
+	str rname;
+	mongodbc_reply_t *reply;
+	str rkey;
+	int rkeyid;
+} mongodbc_pv_t;
+
+/* Server related functions */
+mongodbc_server_t* mongodbc_get_server(str *name);
+int mongodbc_reconnect_server(mongodbc_server_t *rsrv);
+
+/* Command related functions */
+mongodbc_reply_t *mongodbc_get_reply(str *name);
+int mongodbc_free_reply(str *name);
+int mongodbc_next_reply(str *name);
+#endif

+ 365 - 0
modules/ndb_mongodb/ndb_mongodb_mod.c

@@ -0,0 +1,365 @@
+/**
+ * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "../../sr_module.h"
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../trim.h"
+
+#include "mongodb_client.h"
+
+MODULE_VERSION
+
+/** parameters */
+
+int mongodb_srv_param(modparam_t type, void *val);
+static int w_mongodb_find(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres);
+static int w_mongodb_cmd_simple(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres);
+static int w_mongodb_cmd(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres);
+static int fixup_mongodb_cmd(void** param, int param_no);
+static int w_mongodb_free_reply(struct sip_msg* msg, char* res);
+static int w_mongodb_next_reply(struct sip_msg* msg, char* res);
+
+static void mod_destroy(void);
+static int  child_init(int rank);
+
+static int pv_get_mongodb(struct sip_msg *msg,  pv_param_t *param,
+		pv_value_t *res);
+static int pv_parse_mongodb_name(pv_spec_p sp, str *in);
+
+static pv_export_t mod_pvs[] = {
+	{ {"mongodb", sizeof("mongodb")-1}, PVT_OTHER, pv_get_mongodb, 0,
+		pv_parse_mongodb_name, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+
+static cmd_export_t cmds[]={
+	{"mongodb_find", (cmd_function)w_mongodb_find, 5, fixup_mongodb_cmd,
+		0, ANY_ROUTE},
+	{"mongodb_cmd_simple", (cmd_function)w_mongodb_cmd_simple, 5, fixup_mongodb_cmd,
+		0, ANY_ROUTE},
+	{"mongodb_cmd", (cmd_function)w_mongodb_cmd, 5, fixup_mongodb_cmd,
+		0, ANY_ROUTE},
+	{"mongodb_free", (cmd_function)w_mongodb_free_reply, 1, fixup_spve_null,
+		0, ANY_ROUTE},
+	{"mongodb_next", (cmd_function)w_mongodb_next_reply, 1, fixup_spve_null,
+		0, ANY_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={
+	{"server",         PARAM_STRING|USE_FUNC_PARAM, (void*)mongodb_srv_param},
+	{0, 0, 0}
+};
+
+struct module_exports exports = {
+	"ndb_mongodb",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,
+	0,              /* exported MI functions */
+	mod_pvs,        /* exported pseudo-variables */
+	0,              /* extra processes */
+	0,       /* module initialization function */
+	0,              /* response function */
+	mod_destroy,    /* destroy function */
+	child_init      /* per child init function */
+};
+
+
+
+/* each child get a new connection to the database */
+static int child_init(int rank)
+{
+	/* skip child init for non-worker process ranks */
+	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
+		return 0;
+
+	if(mongodbc_init()<0)
+	{
+		LM_ERR("failed to initialize mongodb connections\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ *
+ */
+static void mod_destroy(void)
+{
+	LM_DBG("cleaning up\n");
+	mongodbc_destroy();
+}
+
+/**
+ *
+ */
+static int w_mongodb_do_cmd(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres, int ctype)
+{
+	int ret;
+	str s[5];
+
+	if(fixup_get_svalue(msg, (gparam_t*)ssrv, &s[0])!=0)
+	{
+		LM_ERR("no mongodb server name\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)sdname, &s[1])!=0)
+	{
+		LM_ERR("no mongodb database name\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)scname, &s[2])!=0)
+	{
+		LM_ERR("no mongodb collection name\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)scmd, &s[3])!=0)
+	{
+		LM_ERR("no mongodb command\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)sres, &s[4])!=0)
+	{
+		LM_ERR("no mongodb reply name\n");
+		return -1;
+	}
+	if(ctype==0) {
+		ret = mongodbc_exec_simple(&s[0], &s[1], &s[2], &s[3], &s[4]);
+	} else if(ctype==1) {
+		ret = mongodbc_exec(&s[0], &s[1], &s[2], &s[3], &s[4]);
+	} else {
+		ret = mongodbc_find(&s[0], &s[1], &s[2], &s[3], &s[4]);
+	}
+	if(ret<0)
+		return -1;
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_mongodb_cmd_simple(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres)
+{
+	return w_mongodb_do_cmd(msg, ssrv, sdname, scname, scmd, sres, 0);
+}
+
+/**
+ *
+ */
+static int w_mongodb_cmd(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres)
+{
+	return w_mongodb_do_cmd(msg, ssrv, sdname, scname, scmd, sres, 1);
+}
+
+/**
+ *
+ */
+static int w_mongodb_find(sip_msg_t* msg, char* ssrv, char *sdname, char *scname,
+		char* scmd, char* sres)
+{
+	return w_mongodb_do_cmd(msg, ssrv, sdname, scname, scmd, sres, 2);
+}
+
+/**
+ *
+ */
+static int fixup_mongodb_cmd(void** param, int param_no)
+{
+	return fixup_spve_null(param, 1);
+}
+
+/**
+ *
+ */
+static int w_mongodb_free_reply(struct sip_msg* msg, char* res)
+{
+	str name;
+
+	if(fixup_get_svalue(msg, (gparam_t*)res, &name)!=0)
+	{
+		LM_ERR("no mongodb reply name\n");
+		return -1;
+	}
+
+	if(mongodbc_free_reply(&name)<0)
+		return -1;
+	return 1;
+}
+
+/**
+ *
+ */
+static int w_mongodb_next_reply(struct sip_msg* msg, char* res)
+{
+	str name;
+
+	if(fixup_get_svalue(msg, (gparam_t*)res, &name)!=0)
+	{
+		LM_ERR("no mongodb reply name\n");
+		return -1;
+	}
+
+	if(mongodbc_next_reply(&name)<0)
+		return -1;
+	return 1;;
+}
+
+/**
+ *
+ */
+int mongodb_srv_param(modparam_t type, void *val)
+{
+	return mongodbc_add_server((char*)val);
+}
+
+/**
+ *
+ */
+static int pv_parse_mongodb_name(pv_spec_p sp, str *in)
+{
+	mongodbc_pv_t *rpv=NULL;
+	str pvs;
+	int i;
+
+	if(in->s==NULL || in->len<=0)
+		return -1;
+
+	rpv = (mongodbc_pv_t*)pkg_malloc(sizeof(mongodbc_pv_t));
+	if(rpv==NULL)
+		return -1;
+
+	memset(rpv, 0, sizeof(mongodbc_pv_t));
+
+	pvs = *in;
+	trim(&pvs);
+
+	rpv->rname.s = pvs.s;
+	for(i=0; i<pvs.len-2; i++)
+	{
+		if(isspace(pvs.s[i]) || pvs.s[i]=='=') {
+			rpv->rname.len = i;
+			break;
+		}
+	}
+	rpv->rname.len = i;
+
+	if(rpv->rname.len==0)
+		goto error_var;
+
+	while(i<pvs.len-2 && isspace(pvs.s[i]))
+		i++;
+
+	if(pvs.s[i]!='=')
+		goto error_var;
+
+	if(pvs.s[i+1]!='>')
+		goto error_var;
+
+	i += 2;
+	while(i<pvs.len && isspace(pvs.s[i]))
+		i++;
+
+	if(i>=pvs.len)
+		goto error_key;
+
+	rpv->rkey.s   = pvs.s + i;
+	rpv->rkey.len = pvs.len - i;
+
+	if(rpv->rkey.len>=5 && strncmp(rpv->rkey.s, "value", 5)==0) {
+		rpv->rkeyid = 1;
+	} else if(rpv->rkey.len>=4 && strncmp(rpv->rkey.s, "type", 4)==0) {
+		rpv->rkeyid = 0;
+	} else if(rpv->rkey.len==4 && strncmp(rpv->rkey.s, "info", 4)==0) {
+		rpv->rkeyid = 2;
+	} else if(rpv->rkey.len==4 && strncmp(rpv->rkey.s, "size", 4)==0) {
+		rpv->rkeyid = 3;
+	} else {
+		goto error_key;
+	}
+
+	sp->pvp.pvn.u.dname = (void*)rpv;
+	sp->pvp.pvn.type = PV_NAME_OTHER;
+	return 0;
+
+error_var:
+	LM_ERR("invalid var spec [%.*s]\n", in->len, in->s);
+	pkg_free(rpv);
+	return -1;
+
+error_key:
+	LM_ERR("invalid key spec in [%.*s]\n", in->len, in->s);
+	pkg_free(rpv);
+	return -1;
+}
+
+/**
+ *
+ */
+static int pv_get_mongodb(struct sip_msg *msg,  pv_param_t *param,
+		pv_value_t *res)
+{
+	mongodbc_pv_t *rpv;
+
+	rpv = (mongodbc_pv_t*)param->pvn.u.dname;
+	if(rpv->reply==NULL)
+	{
+		rpv->reply = mongodbc_get_reply(&rpv->rname);
+		if(rpv->reply==NULL)
+			return pv_get_null(msg, param, res);
+	}
+
+
+	switch(rpv->rkeyid) {
+		case 1:
+			/* value */
+			if(rpv->reply->jsonrpl.s==NULL)
+				return pv_get_null(msg, param, res);
+			return pv_get_strval(msg, param, res, &rpv->reply->jsonrpl);
+		case 2:
+			/* info */
+			return pv_get_null(msg, param, res);
+		case 3:
+			/* size */
+			return pv_get_null(msg, param, res);
+		case 0:
+			/* type */
+			return pv_get_sintval(msg, param, res, 0);
+		default:
+			/* We do nothing. */
+			return pv_get_null(msg, param, res);
+	}
+}