mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
11 KiB
515 lines
11 KiB
/**
|
|
* 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"
|
|
#include "api.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 nres;
|
|
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 {
|
|
nres = 0;
|
|
if(emode==3) nres = 1; /* return one result */
|
|
rpl->cursor = mongoc_collection_find (rpl->collection,
|
|
MONGOC_QUERY_NONE,
|
|
0,
|
|
nres,
|
|
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);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int mongodbc_find_one(str *srv, str *dname, str *cname, str *cmd, str *res)
|
|
{
|
|
return mongodbc_exec_cmd(srv, dname, cname, cmd, res, 3);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
int bind_ndb_mongodb(ndb_mongodb_api_t* api)
|
|
{
|
|
if (!api) {
|
|
ERR("Invalid parameter value\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(api, 0, sizeof(ndb_mongodb_api_t));
|
|
api->cmd = mongodbc_exec;
|
|
api->cmd_simple = mongodbc_exec_simple;
|
|
api->find = mongodbc_find;
|
|
api->find_one = mongodbc_find_one;
|
|
api->next_reply = mongodbc_next_reply;
|
|
api->free_reply = mongodbc_free_reply;
|
|
|
|
return 0;
|
|
}
|
|
|