1
0
mirror of https://github.com/coturn/coturn.git synced 2025-10-24 12:31:00 +02:00

MongoDB support: initial checkin

This commit is contained in:
mom040267 2014-07-11 07:06:05 +00:00
parent 48537e9624
commit 5c3b773d9c
22 changed files with 4262 additions and 2472 deletions

67
INSTALL
View File

@ -212,13 +212,13 @@ do not allows that, then after the installation, you may have to adjust the
system-wide shared library search path by using "ldconfig -n <libdirname>" system-wide shared library search path by using "ldconfig -n <libdirname>"
(Linux), "ldconfig -m <libdirname>" (BSD) or "crle -u -l <libdirname>" (Linux), "ldconfig -m <libdirname>" (BSD) or "crle -u -l <libdirname>"
(Solaris). Your system must be able to find the libevent2, openssl and (Solaris). Your system must be able to find the libevent2, openssl and
(optionally) PostgreSQL and/or MySQL (MariaDB) and/or Redis shared libraries, (optionally) PostgreSQL and/or MySQL (MariaDB) and/or MongoDB and/or Redis
either with the help of the system-wide library search configuration or by shared libraries, either with the help of the system-wide library search
using LD_LIBRARY_PATH. "make install" will make a non-garantied effort to add configuration or by using LD_LIBRARY_PATH. "make install" will make a
automatically PREFIX/lib and /usr/local/lib to the libraries search path, non-garantied effort to add automatically PREFIX/lib and /usr/local/lib to
but if you have some libraries in different non-default directories the libraries search path, but if you have some libraries in different
you will have to add them manually to the search path, or you non-default directories you will have to add them manually to the search
will have to adjust LD_LIBRARY_PATH. path, or you will have to adjust LD_LIBRARY_PATH.
V. PLATFORMS V. PLATFORMS
@ -277,8 +277,8 @@ VII. WHICH EXTRA LIBRARIES AND UTILITIES YOU NEED
In addition to common *NIX OS services and libraries, to compile this code, In addition to common *NIX OS services and libraries, to compile this code,
OpenSSL (version 1.0.0a or better recommended) and libevent2 (version 2.0.5 OpenSSL (version 1.0.0a or better recommended) and libevent2 (version 2.0.5
or better) are required, the PostgreSQL C client development setup is or better) are required, the PostgreSQL C client development setup is
optional, the MySQL (MariaDB) C client development setup is optional, and the optional, the MySQL (MariaDB) C client development setup is optional, the MongoDB
Hiredis development files for Redis database access are optional. C Driver and the Hiredis development files for Redis database access are optional.
For fully functional build, the extra set of libraries must be installed For fully functional build, the extra set of libraries must be installed
in full version (the development headers and the libraries to link with). in full version (the development headers and the libraries to link with).
For runtime, only runtime setup is required. If the build is modified for For runtime, only runtime setup is required. If the build is modified for
@ -290,6 +290,7 @@ libraries can be downloaded from their web sites:
- http://www.libevent.org (required); - http://www.libevent.org (required);
- http://www.postgresql.org (optional); - http://www.postgresql.org (optional);
- http://www.mysql.org (or http://mariadb.org) (optional); - http://www.mysql.org (or http://mariadb.org) (optional);
- https://github.com/mongodb/mongo-c-driver (optional);
- http://redis.io (optional). - http://redis.io (optional).
The installations are pretty straightforward - the usual The installations are pretty straightforward - the usual
@ -352,6 +353,11 @@ installation:
- you have to install gcc first: - you have to install gcc first:
$ sudo yum install gcc $ sudo yum install gcc
- mongo-c-driver packages are not available. MongoDB support
will not be compiled, unless you install it "manually" before
the TURN server compilation. Refer to https://github.com/mongodb/mongo-c-driver
for installation instructions of the driver.
- hiredis packages are not available, so do not issue the - hiredis packages are not available, so do not issue the
hiredis installation commands. Redis support will not be hiredis installation commands. Redis support will not be
compiled, unless you install it "manually" before the TURN compiled, unless you install it "manually" before the TURN
@ -381,7 +387,7 @@ like this:
Dynamic library paths: Dynamic library paths:
You may also have to adjust the turn server start script, add PostgreSQL You may also have to adjust the turn server start script, add PostgreSQL
and/or MySQL and/or Redis runtime library path to LD_LIBRARY_PATH. and/or MySQL and/or MongoDB and/or Redis runtime library path to LD_LIBRARY_PATH.
Or you may find that it would be more convenient to adjust the Or you may find that it would be more convenient to adjust the
system-wide shared library search path by using commands: system-wide shared library search path by using commands:
@ -412,17 +418,17 @@ absolute paths or @rpath/... .
See also the next section. See also the next section.
NOTE: See "PostgreSQL setup" and "MySQL setup" and "Redis setup" sections NOTE: See "PostgreSQL setup" and "MySQL setup" and "MongoDB setup" and
below for more database setup information. "Redis setup" sections below for more database setup information.
NOTE: If you do not install PostgreSQL or MySQL or Redis then you will NOTE: If you do not install PostgreSQL or MySQL or MongoDB or Redis then you will
be limited to flat files for user database. It will work great for be limited to flat files for user database. It will work great for
smaller user databases (like 100 users) but for larger systems you smaller user databases (like 100 users) but for larger systems you
will need PostgreSQL or MySQL or Redis. will need PostgreSQL or MySQL or MongoDB or Redis.
NOTE: To run PostgreSQL or MySQL or Redis server on the same system, NOTE: To run PostgreSQL or MySQL or MongoDB or Redis server on the same system,
you will also have to install a corresponding PostgreSQL or MySQL or you will also have to install a corresponding PostgreSQL or MySQL or
Redis server package. The DB C development packages only provide MongoDB or Redis server package. The DB C development packages only provide
development libraries, and client libraries only provide client development libraries, and client libraries only provide client
access utilities and runtime libraries. The server packages may access utilities and runtime libraries. The server packages may
include everything - client, C development and server runtime. include everything - client, C development and server runtime.
@ -892,7 +898,28 @@ Or in the turnserver.conf file:
mysql-userdb="host=localhost dbname=turn user=turn password=turn connect_timeout=30" mysql-userdb="host=localhost dbname=turn user=turn password=turn connect_timeout=30"
XVI. Redis setup XVI. MongoDB setup
The MongoDB setup is well documented on their site http://docs.mongodb.org/manual/.
If the TURN server was compiled with MongoDB support (mongo-c-driver is the C client
library for MongoDB), then we can use the TURN server database parameter
--mongo-userdb. The value of this parameter is a connection string
for the MongoDB database. The format of the connection string is described at
http://hergert.me/docs/mongo-c-driver/mongoc_uri.html:
"mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]"
So, an example of the MongoDB database parameter in the TURN server command
line would be:
--mongo-userdb="mongodb://localhost:27017/turndb"
Or in the turnserver.conf file:
mongo-userdb="mongodb://localhost:27017/turndb"
XVII. Redis setup
The Redis setup is well documented on their site http://redis.io. The Redis setup is well documented on their site http://redis.io.
The TURN Server Redis database schema description can be found The TURN Server Redis database schema description can be found
@ -961,20 +988,20 @@ Redis TURN admin commands:
$ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u gorst -r north.gov -p hero $ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u gorst -r north.gov -p hero
$ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic $ bin/turnadmin -A -N "host=localhost dbname=0 user=turn password=turn" -u ninefingers -r north.gov -p youhavetoberealistic
XV. Performance tuning XVIII. Performance tuning
This topic is covered in the wiki page: This topic is covered in the wiki page:
http://code.google.com/p/coturn/wiki/turn_performance_and_load_balance http://code.google.com/p/coturn/wiki/turn_performance_and_load_balance
XVI. TURN Server setup XIX. TURN Server setup
Read the project wiki pages: http://code.google.com/p/coturn/w/list Read the project wiki pages: http://code.google.com/p/coturn/w/list
Also, check the project from page links to the TURN/WebRTC configuration examples. Also, check the project from page links to the TURN/WebRTC configuration examples.
It may give you an idea how it can be done. It may give you an idea how it can be done.
XVI. Management interface XX. Management interface
You have a telnet interface (enabled by default) to access the turnserver process, You have a telnet interface (enabled by default) to access the turnserver process,
to view its state, to gather some statistical information, and to make some changes to view its state, to gather some statistical information, and to make some changes

View File

@ -27,8 +27,11 @@ IMPL_DEPS = ${COMMON_DEPS} ${IMPL_HEADERS} ${IMPL_MODS}
HIREDIS_HEADERS = src/apps/common/hiredis_libevent2.h HIREDIS_HEADERS = src/apps/common/hiredis_libevent2.h
HIREDIS_MODS = src/apps/common/hiredis_libevent2.c HIREDIS_MODS = src/apps/common/hiredis_libevent2.c
SERVERAPP_HEADERS = src/apps/relay/userdb.h src/apps/relay/tls_listener.h src/apps/relay/mainrelay.h src/apps/relay/turncli.h src/apps/relay/dtls_listener.h src/apps/relay/libtelnet.h ${HIREDIS_HEADERS} USERDB_HEADERS = src/apps/relay/dbdrivers/dbdriver.h src/apps/relay/dbdrivers/dbd_pgsql.h src/apps/relay/dbdrivers/dbd_mysql.h src/apps/relay/dbdrivers/dbd_mongo.h src/apps/relay/dbdrivers/dbd_redis.h
SERVERAPP_MODS = src/apps/relay/mainrelay.c src/apps/relay/netengine.c src/apps/relay/libtelnet.c src/apps/relay/turncli.c src/apps/relay/userdb.c src/apps/relay/tls_listener.c src/apps/relay/dtls_listener.c ${HIREDIS_MODS} USERDB_MODS = src/apps/relay/dbdrivers/dbdriver.c src/apps/relay/dbdrivers/dbd_pgsql.c src/apps/relay/dbdrivers/dbd_mysql.c src/apps/relay/dbdrivers/dbd_mongo.c src/apps/relay/dbdrivers/dbd_redis.c
SERVERAPP_HEADERS = src/apps/relay/userdb.h src/apps/relay/tls_listener.h src/apps/relay/mainrelay.h src/apps/relay/turncli.h src/apps/relay/dtls_listener.h src/apps/relay/libtelnet.h ${HIREDIS_HEADERS} ${USERDB_HEADERS}
SERVERAPP_MODS = src/apps/relay/mainrelay.c src/apps/relay/netengine.c src/apps/relay/libtelnet.c src/apps/relay/turncli.c src/apps/relay/userdb.c src/apps/relay/tls_listener.c src/apps/relay/dtls_listener.c ${HIREDIS_MODS} ${USERDB_MODS}
SERVERAPP_DEPS = ${SERVERTURN_MODS} ${SERVERTURN_DEPS} ${SERVERAPP_MODS} ${SERVERAPP_HEADERS} ${COMMON_DEPS} ${IMPL_DEPS} lib/libturnclient.a SERVERAPP_DEPS = ${SERVERTURN_MODS} ${SERVERTURN_DEPS} ${SERVERAPP_MODS} ${SERVERAPP_HEADERS} ${COMMON_DEPS} ${IMPL_DEPS} lib/libturnclient.a
TURN_BUILD_RESULTS = bin/turnutils_stunclient bin/turnutils_rfc5769check bin/turnutils_uclient bin/turnserver bin/turnutils_peer lib/libturnclient.a include/turn/ns_turn_defs.h TURN_BUILD_RESULTS = bin/turnutils_stunclient bin/turnutils_rfc5769check bin/turnutils_uclient bin/turnserver bin/turnutils_peer lib/libturnclient.a include/turn/ns_turn_defs.h

View File

@ -92,6 +92,8 @@ Options with required values:
See the --psql-userdb option in the turnserver section. See the --psql-userdb option in the turnserver section.
-M, --mysql-userdb MySQL user database connection string. -M, --mysql-userdb MySQL user database connection string.
See the --mysql-userdb option in the turnserver section. See the --mysql-userdb option in the turnserver section.
-J, --mongo-userdb MongoDB user database connection string.
See the --mysql-mongo option in the turnserver section.
-N, --redis-userdb Redis user database connection string. -N, --redis-userdb Redis user database connection string.
See the --redis-userdb option in the turnserver section. See the --redis-userdb option in the turnserver section.
-u, --user User name. -u, --user User name.

View File

@ -57,7 +57,7 @@ turnserver - a TURN relay server implementation.
SYNOPSIS SYNOPSIS
$ turnserver [-n | -c <config-file> ] [flags] [ --userdb=<userdb-file> | --psql-userdb=<db-conn-string> | --mysql-userdb=<db-conn-string> | --redis-userdb=<db-conn-string> ] [-z | --no-auth | -a | --lt-cred-mech ] [options] $ turnserver [-n | -c <config-file> ] [flags] [ --userdb=<userdb-file> | --psql-userdb=<db-conn-string> | --mysql-userdb=<db-conn-string> | --mongo-userdb=<db-conn-string> | --redis-userdb=<db-conn-string> ] [-z | --no-auth | -a | --lt-cred-mech ] [options]
$ turnserver -h $ turnserver -h
DESCRIPTION DESCRIPTION
@ -113,6 +113,17 @@ User database settings:
Also, see http://www.mysql.org or http://mariadb.org Also, see http://www.mysql.org or http://mariadb.org
for full MySQL documentation. for full MySQL documentation.
-J, --mongo-userdb User database connection string for MongoDB.
This database can be used for long-term and short-term credentials mechanisms,
and it can store the secret value for secret-based timed authentication in TURN RESP API.
The connection string format is like that:
"mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]"
See the INSTALL file for more explanations and examples.
Also, see http://docs.mongodb.org/manual/
for full MongoDB documentation.
-N, --redis-userdb User database connection string for Redis. -N, --redis-userdb User database connection string for Redis.
This database can be used for long-term and short-term credentials mechanisms, This database can be used for long-term and short-term credentials mechanisms,
and it can store the secret value for secret-based timed authentication in TURN RESP API. and it can store the secret value for secret-based timed authentication in TURN RESP API.
@ -138,9 +149,9 @@ Flags:
-a, --lt-cred-mech Use long-term credentials mechanism (this one you need for WebRTC usage). -a, --lt-cred-mech Use long-term credentials mechanism (this one you need for WebRTC usage).
This option can be used with either flat file user database or This option can be used with either flat file user database or
PostgreSQL DB or MySQL DB or Redis for user keys storage. PostgreSQL DB or MySQL DB or MongoDB or Redis for user keys storage.
-A, --st-cred-mech Use the short-term credentials mechanism. This option requires -A, --st-cred-mech Use the short-term credentials mechanism. This option requires
a PostgreSQL or MySQL or Redis DB for short term passwords storage. a PostgreSQL or MySQL or MongoDB or Redis DB for short term passwords storage.
-z, --no-auth Do not use any credentials mechanism, allow anonymous access. -z, --no-auth Do not use any credentials mechanism, allow anonymous access.
Opposite to -a and -A options. This is default option when no Opposite to -a and -A options. This is default option when no
@ -461,7 +472,7 @@ Options with required values:
no Redis stats DB used). This database keeps allocations status information, and it can no Redis stats DB used). This database keeps allocations status information, and it can
be also used for publishing and delivering traffic and allocation event notifications. be also used for publishing and delivering traffic and allocation event notifications.
This database option can be used independently of --redis-userdb option, This database option can be used independently of --redis-userdb option,
and actually Redis can be used for status/statistics and MySQL or PostgreSQL can and actually Redis can be used for status/statistics and MySQL or MongoDB or PostgreSQL can
be used for the user database. be used for the user database.
The connection string has the same parameters as redis-userdb connection string. The connection string has the same parameters as redis-userdb connection string.
@ -533,7 +544,7 @@ for that you have a number of options:
b) userdb config file. b) userdb config file.
c) a database table (PostgreSQL or MySQL). You will have to set keys with c) a database table (PostgreSQL or MySQL or MongoDB). You will have to set keys with
turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords turnadmin utility (see docs and wiki for turnadmin). You cannot use open passwords
in the database. in the database.
@ -717,7 +728,9 @@ turndb/testredisdbsetup.sh as an example.
can be administered separately, and each realm can have its own set of users and its own can be administered separately, and each realm can have its own set of users and its own
performance options (max-bps, user-quota, total-quota). performance options (max-bps, user-quota, total-quota).
7) Of course, the turnserver can be used in non-secure mode, when users are allowed to establish 7) If you use MongoDB, the database will be setup for you automatically.
8) Of course, the turnserver can be used in non-secure mode, when users are allowed to establish
sessions anonymously. But in most cases (like WebRTC) that will not work. sessions anonymously. But in most cases (like WebRTC) that will not work.
For the status and statistics database, there are two choices: For the status and statistics database, there are two choices:

56
configure vendored
View File

@ -13,6 +13,8 @@ cleanup() {
rm -rf ${PQ_TMPCPROGB} rm -rf ${PQ_TMPCPROGB}
rm -rf ${MYSQL_TMPCPROGC} rm -rf ${MYSQL_TMPCPROGC}
rm -rf ${MYSQL_TMPCPROGB} rm -rf ${MYSQL_TMPCPROGB}
rm -rf ${MONGO_TMPCPROGC}
rm -rf ${MONGO_TMPCPROGB}
rm -rf ${D_TMPCPROGC} rm -rf ${D_TMPCPROGC}
rm -rf ${D_TMPCPROGB} rm -rf ${D_TMPCPROGB}
rm -rf ${E_TMPCPROGC} rm -rf ${E_TMPCPROGC}
@ -124,6 +126,30 @@ testlibmysql() {
fi fi
} }
testlibmongoc() {
for inc in ${PREFIX}/libmongoc-1.0 ${PREFIX}/libbson-1.0 /usr/local/include/libmongoc-1.0 /usr/local/include/libbson-1.0 /usr/libmongoc-1.0 -I/usr/libbson-1.0
do
if [ -d ${inc} ] ; then
MONGO_CFLAGS="${MONGO_CFLAGS} -I${inc}"
fi
done
MONGO_LIBS="-lmongoc-1.0 -lbson-1.0"
${CC} ${MONGO_TMPCPROGC} -o ${MONGO_TMPCPROGB} ${OSCFLAGS} ${DBCFLAGS} ${DBLIBS} ${MONGO_CFLAGS} ${MONGO_LIBS} ${OSLIBS} 2>>/dev/null
ER=$?
if ! [ ${ER} -eq 0 ] ; then
${ECHO_CMD}
${ECHO_CMD} "MONGODB DEVELOPMENT LIBRARIES (libmongoc-1.0 and libbson-1.0) AND/OR HEADER (mongoc.h)"
${ECHO_CMD} " ARE NOT INSTALLED PROPERLY ON THIS SYSTEM."
${ECHO_CMD} " THAT'S OK BUT THE TURN SERVER IS BUILDING WITHOUT MONGODB SUPPORT."
${ECHO_CMD}
return 0
else
DBCFLAGS="${DBCFLAGS} ${MONGO_CFLAGS}"
DBLIBS="${DBLIBS} ${MONGO_LIBS}"
return 1
fi
}
testlib() { testlib() {
testlibraw l${1} testlibraw l${1}
} }
@ -666,6 +692,19 @@ int main(int argc, char** argv) {
} }
! !
MONGO_TMPCPROG=__test__ccomp__libmongoc__$$
MONGO_TMPCPROGC=${TMPDIR}/${MONGO_TMPCPROG}.c
MONGO_TMPCPROGB=${TMPDIR}/${MONGO_TMPCPROG}
cat > ${MONGO_TMPCPROGC} <<!
#include <mongoc.h>
int main(int argc, char** argv) {
return (argc+
(int)(mongoc_client_new("mongodb://localhost:27017")!=0)+
(int)(argv[0][0]));
}
!
########################## ##########################
# What is our compiler ? # What is our compiler ?
########################## ##########################
@ -940,6 +979,23 @@ else
TURN_NO_MYSQL="-DTURN_NO_MYSQL" TURN_NO_MYSQL="-DTURN_NO_MYSQL"
fi fi
###########################
# Test MongoDB
###########################
if [ -z "${TURN_NO_MONGO}" ] ; then
testlibmongoc
ER=$?
if ! [ ${ER} -eq 0 ] ; then
${ECHO_CMD} "MongoDB found."
else
TURN_NO_MYSQL="-DTURN_NO_MONGO"
fi
else
TURN_NO_MYSQL="-DTURN_NO_MONGO"
fi
########################### ###########################
# Test Redis # Test Redis
########################### ###########################

View File

@ -161,14 +161,14 @@
# Uncomment to use long-term credential mechanism. # Uncomment to use long-term credential mechanism.
# By default no credentials mechanism is used (any user allowed). # By default no credentials mechanism is used (any user allowed).
# This option can be used with either flat file user database or # This option can be used with either flat file user database or
# PostgreSQL DB or MySQL DB or Redis DB for user keys storage. # PostgreSQL DB or MySQL DB or MongoDB or Redis DB for user keys storage.
# #
#lt-cred-mech #lt-cred-mech
# Uncomment to use short-term credential mechanism. # Uncomment to use short-term credential mechanism.
# By default no credentials mechanism is used (any user allowed). # By default no credentials mechanism is used (any user allowed).
# For short-term credential mechanism you have to use PostgreSQL or # For short-term credential mechanism you have to use PostgreSQL or
# MySQL or Redis database for user password storage. # MySQL or MongoDB or Redis database for user password storage.
# #
#st-cred-mech #st-cred-mech
@ -241,7 +241,7 @@
# 'Dynamic' user accounts database file name. # 'Dynamic' user accounts database file name.
# Only users for long-term mechanism can be stored in a flat file, # Only users for long-term mechanism can be stored in a flat file,
# short-term mechanism will not work with option, the short-term # short-term mechanism will not work with option, the short-term
# mechanism required PostgreSQL or MySQL or Redis database. # mechanism required PostgreSQL or MySQL or MongoDB or Redis database.
# 'Dynamic' long-term user accounts are dynamically checked by the turnserver process, # 'Dynamic' long-term user accounts are dynamically checked by the turnserver process,
# so that they can be changed while the turnserver is running. # so that they can be changed while the turnserver is running.
# #
@ -268,6 +268,14 @@
# #
#mysql-userdb="host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> port=<port> connect_timeout=<seconds>" #mysql-userdb="host=<host> dbname=<database-name> user=<database-user> password=<database-user-password> port=<port> connect_timeout=<seconds>"
# MongoDB database connection string in the case that we are using MongoDB
# as the user database.
# This database can be used for long-term and short-term credential mechanisms
# and it can store the secret value for secret-based timed authentication in TURN RESP API.
# Use string format is described at http://hergert.me/docs/mongo-c-driver/mongoc_uri.html
#
#mongo-userdb="mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]"
# Redis database connection string in the case that we are using Redis # Redis database connection string in the case that we are using Redis
# as the user database. # as the user database.
# This database can be used for long-term and short-term credential mechanisms # This database can be used for long-term and short-term credential mechanisms

View File

@ -10,7 +10,7 @@ service, you have to:
b) For user accounts settings, if using the turnserver b) For user accounts settings, if using the turnserver
with authentication: create and edit /etc/turnuserdb.conf with authentication: create and edit /etc/turnuserdb.conf
file, or set up PostgreSQL or MySQL or Redis database for user accounts. file, or set up PostgreSQL or MySQL or MongoDB or Redis database for user accounts.
Use /usr/local/etc/turnuserdb.conf.default as example for flat file DB, Use /usr/local/etc/turnuserdb.conf.default as example for flat file DB,
or use /usr/local/share/turnserver/schema.sql as SQL database schema, or use /usr/local/share/turnserver/schema.sql as SQL database schema,
or use /usr/local/share/turnserver/schema.userdb.redis as Redis or use /usr/local/share/turnserver/schema.userdb.redis as Redis

View File

@ -0,0 +1,916 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "../mainrelay.h"
#include "dbd_mongo.h"
#if !defined(TURN_NO_MONGO)
#include <mongoc.h>
#include <bson.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////
const char * MONGO_DEFAULT_DB = "turn";
struct _MONGO {
mongoc_uri_t * uri;
mongoc_client_t * client;
const char * database;
};
typedef struct _MONGO MONGO;
static void mongo_logger(mongoc_log_level_t log_level, const char * log_domain, const char * message, void * user_data) {
UNUSED_ARG(log_domain);
UNUSED_ARG(user_data);
TURN_LOG_LEVEL l;
switch(log_level) {
case MONGOC_LOG_LEVEL_ERROR:
l = TURN_LOG_LEVEL_ERROR;
break;
case MONGOC_LOG_LEVEL_WARNING:
l = TURN_LOG_LEVEL_WARNING;
break;
default:
l = TURN_LOG_LEVEL_INFO;
break;
}
TURN_LOG_FUNC(l, "%s\n", message);
}
static void MongoFree(MONGO * info) {
if(info) {
if(info->uri) mongoc_uri_destroy(info->uri);
if(info->client) mongoc_client_destroy(info->client);
turn_free(info, sizeof(MONGO));
}
}
static MONGO * get_mydb_connection(const char *realm) {
UNUSED_ARG(realm);
persistent_users_db_t * pud = get_persistent_users_db();
MONGO * mydbconnection = (MONGO *)(pud->connection);
if(!mydbconnection) {
mongoc_init();
mongoc_log_set_handler(&mongo_logger, NULL);
mydbconnection = (MONGO *)turn_malloc(sizeof(MONGO));
mydbconnection->uri = mongoc_uri_new(pud->userdb);
if (!mydbconnection->uri) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open parse MongoDB URI <%s>, connection string format error\n", pud->userdb);
MongoFree(mydbconnection);
mydbconnection = NULL;
} else {
mydbconnection->client = mongoc_client_new_from_uri(mydbconnection->uri);
if (!mydbconnection->client) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot initialize MongoDB connection\n");
MongoFree(mydbconnection);
mydbconnection = NULL;
} else {
mydbconnection->database = mongoc_uri_get_database(mydbconnection->uri);
if (!mydbconnection->database) mydbconnection->database = MONGO_DEFAULT_DB;
pud->connection = mydbconnection;
}
}
}
return mydbconnection;
}
static mongoc_collection_t * mongo_get_collection(const char * name) {
MONGO * mc = get_mydb_connection(NULL);
if(!mc) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error gettting a connection to MongoDB\n");
return NULL;
}
mongoc_collection_t * collection;
collection = mongoc_client_get_collection(mc->client, mc->database, name);
if (!collection) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MongoDB collection '%s'\n", name);
}
return collection;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static int mongo_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("turn_secret");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "value", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'turn_secret'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
while(mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "value") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
add_to_secrets_list(sl, value);
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
mongoc_collection_t * collection = mongo_get_collection("turnusers_lt");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "name", (const char *)usname);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "hmackey", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'turnusers_lt'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
if (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "hmackey") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
size_t sz = get_hmackey_size(turn_params.shatype) * 2;
if(length < sz) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key format: string length=%d (must be %d): user %s\n", (int)length, (int)sz, usname);
} else {
char kval[sizeof(hmackey_t) + sizeof(hmackey_t) + 1];
ns_bcopy(value, kval, sz);
kval[sz] = 0;
if(convert_string_key_to_binary(kval, key, sz / 2) < 0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n", kval, usname);
} else {
ret = 0;
}
}
}
}
mongoc_cursor_destroy(cursor);
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_get_user_pwd(u08bits *usname, st_password_t pwd) {
mongoc_collection_t * collection = mongo_get_collection("turnusers_st");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "name", (const char *)usname);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "password", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 1, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'turnusers_st'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
if (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "password") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
if(length < 1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password data for user %s, size in MongoDB is zero(0)\n", usname);
} else {
ns_bcopy(value, pwd, length);
pwd[length] = 0;
ret = 0;
}
}
}
mongoc_cursor_destroy(cursor);
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
mongoc_collection_t * collection = mongo_get_collection("turnusers_lt");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "name", (const char *)usname);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_t doc;
bson_init(&doc);
BSON_APPEND_UTF8(&doc, "name", (const char *)usname);
BSON_APPEND_UTF8(&doc, "realm", (const char *)realm);
BSON_APPEND_UTF8(&doc, "hmackey", (const char *)key);
int ret = -1;
if (!mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &query, &doc, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating secret key information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&doc);
bson_destroy(&query);
return ret;
}
static int mongo_set_user_pwd(u08bits *usname, st_password_t pwd) {
mongoc_collection_t * collection = mongo_get_collection("turnusers_st");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "name", (const char *)usname);
bson_t doc;
bson_init(&doc);
BSON_APPEND_UTF8(&doc, "name", (const char *)usname);
BSON_APPEND_UTF8(&doc, "password", (const char *)pwd);
int ret = -1;
if (!mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &query, &doc, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating secret key information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&doc);
bson_destroy(&query);
return ret;
}
static int mongo_del_user(u08bits *usname, int is_st, u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection(is_st ? "turnusers_st" : "turnusers_lt");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "name", (const char *)usname);
if(!is_st) {
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
}
int ret = -1;
if (!mongoc_collection_delete(collection, MONGOC_DELETE_SINGLE_REMOVE, &query, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting user key information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
return ret;
}
static int mongo_list_users(int is_st, u08bits *realm) {
const char * collection_name = is_st ? "turnusers_st" : "turnusers_lt";
mongoc_collection_t * collection = mongo_get_collection(collection_name);
if(!collection)
return -1;
bson_t query, child;
bson_init(&query);
bson_append_document_begin(&query, "$orderby", -1, &child);
bson_append_int32(&child, "name", -1, 1);
bson_append_document_end(&query, &child);
bson_append_document_begin(&query, "$query", -1, &child);
if (!is_st && realm && realm[0]) {
BSON_APPEND_UTF8(&child, "realm", (const char *)realm);
}
bson_append_document_end(&query, &child);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "name", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection '%s'\n", collection_name);
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
while (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "name") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
if (length) {
printf("%s\n", value);
}
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_show_secret(u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("turn_secret");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "value", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'turn_secret'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
while (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "value") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
if (length) {
printf("%s\n", value);
}
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_del_secret(u08bits *secret, u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("turn_secret");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
if(secret && (secret[0]!=0)) {
BSON_APPEND_UTF8(&query, "value", (const char *)secret);
}
mongoc_collection_delete(collection, 0, &query, NULL, NULL);
mongoc_collection_destroy(collection);
bson_destroy(&query);
return 0;
}
static int mongo_set_secret(u08bits *secret, u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("turn_secret");
if(!collection)
return -1;
bson_t query;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
BSON_APPEND_UTF8(&query, "value", (const char *)secret);
int res = mongoc_collection_insert(collection, MONGOC_INSERT_NONE, &query, NULL, NULL);
mongoc_collection_destroy(collection);
bson_destroy(&query);
if (!res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating secret key information\n");
return -1;
} else {
return 0;
}
}
static int mongo_add_origin(u08bits *origin, u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return -1;
int ret = -1;
bson_t query, doc, child;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_init(&doc);
bson_append_document_begin(&doc, "$addToSet", -1, &child);
BSON_APPEND_UTF8(&child, "origin", (const char *)origin);
bson_append_document_end(&doc, &child);
if (!mongoc_collection_update(collection, MONGOC_UPDATE_UPSERT, &query, &doc, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating realm origin information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&doc);
return ret;
}
static int mongo_del_origin(u08bits *origin) {
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return -1;
int ret = -1;
bson_t query, doc, child;
bson_init(&query);
bson_init(&doc);
bson_append_document_begin(&doc, "$pull", -1, &child);
BSON_APPEND_UTF8(&child, "origin", (const char *)origin);
bson_append_document_end(&doc, &child);
if (!mongoc_collection_update(collection, MONGOC_UPDATE_MULTI_UPDATE, &query, &doc, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting origin information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&doc);
return ret;
}
static int mongo_list_origins(u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return -1;
bson_t query, child;
bson_init(&query);
bson_append_document_begin(&query, "$orderby", -1, &child);
BSON_APPEND_INT32(&child, "realm", 1);
bson_append_document_end(&query, &child);
bson_append_document_begin(&query, "$query", -1, &child);
if (realm && realm[0]) {
BSON_APPEND_UTF8(&child, "realm", (const char *)realm);
}
bson_append_document_end(&query, &child);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "origin", 1);
BSON_APPEND_INT32(&fields, "realm", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'realm'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
while (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
const char * _realm = bson_iter_utf8(&iter, &length);
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "origin") && BSON_ITER_HOLDS_ARRAY(&iter)) {
const uint8_t *docbuf = NULL;
uint32_t doclen = 0;
bson_t origin_array;
bson_iter_t origin_iter;
bson_iter_array(&iter, &doclen, &docbuf);
bson_init_static(&origin_array, docbuf, doclen);
if (bson_iter_init(&origin_iter, &origin_array)) {
while(bson_iter_next(&origin_iter)) {
if (BSON_ITER_HOLDS_UTF8(&origin_iter)) {
const char * _origin = bson_iter_utf8(&origin_iter, &length);
printf("%s ==>> %s\n", _realm, _origin);
}
}
}
}
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static int mongo_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return -1;
bson_t query, doc, child;
bson_init(&query);
BSON_APPEND_UTF8(&query, "realm", (const char *)realm);
bson_init(&doc);
char * _k = (char *)turn_malloc(9 + strlen(opt));
strcpy(_k, "options.");
strcat(_k, opt);
if (value > 0) {
bson_append_document_begin(&doc, "$set", -1, &child);
BSON_APPEND_INT32(&child, _k, (int32_t)value);
bson_append_document_end(&doc, &child);
} else {
bson_append_document_begin(&doc, "$unset", -1, &child);
BSON_APPEND_INT32(&child, _k, 1);
bson_append_document_end(&doc, &child);
}
free(_k);
int ret = -1;
if (!mongoc_collection_update(collection, MONGOC_UPDATE_MULTI_UPDATE, &query, &doc, NULL, NULL)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting origin information\n");
} else {
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&doc);
return ret;
}
static int mongo_list_realm_options(u08bits *realm) {
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return -1;
bson_t query, child;
bson_init(&query);
bson_append_document_begin(&query, "$orderby", -1, &child);
BSON_APPEND_INT32(&child, "realm", 1);
bson_append_document_end(&query, &child);
bson_append_document_begin(&query, "$query", -1, &child);
if (realm && realm[0]) {
BSON_APPEND_UTF8(&child, "realm", (const char *)realm);
}
bson_append_document_end(&query, &child);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "options", 1);
BSON_APPEND_INT32(&fields, "realm", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'realm'\n");
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
while (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
const char * _realm = bson_iter_utf8(&iter, &length);
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "options") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
const uint8_t *docbuf = NULL;
uint32_t doclen = 0;
bson_t options;
bson_iter_t options_iter;
bson_iter_document(&iter, &doclen, &docbuf);
bson_init_static(&options, docbuf, doclen);
if (bson_iter_init(&options_iter, &options)) {
while(bson_iter_next(&options_iter)) {
const char * _k = bson_iter_key(&options_iter);
printf("key %s, type %d\n", _k, bson_iter_type(&options_iter));
if (BSON_ITER_HOLDS_DOUBLE(&options_iter)) {
int32_t _v = (int32_t)bson_iter_double(&options_iter);
printf("%s[%s]=%d\n", _k, _realm, _v);
} else if (BSON_ITER_HOLDS_INT32(&options_iter)) {
int32_t _v = bson_iter_int32(&options_iter);
printf("%s[%s]=%d\n", _k, _realm, _v);
} else if (BSON_ITER_HOLDS_INT64(&options_iter)) {
int32_t _v = (int32_t)bson_iter_int64(&options_iter);
printf("%s[%s]=%d\n", _k, _realm, _v);
}
}
}
}
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static void mongo_auth_ping(void * rch) {
UNUSED_ARG(rch);
// NOOP
}
static int mongo_get_ip_list(const char *kind, ip_range_list_t * list) {
char * collection_name = (char *)turn_malloc(strlen(kind) + 9);
sprintf(collection_name, "%s_peer_ip", kind);
mongoc_collection_t * collection = mongo_get_collection(collection_name);
turn_free(collection_name, strlen(kind) + 9);
if(!collection)
return -1;
bson_t query;
bson_init(&query);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "ip_range", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
int ret = -1;
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection '%s'\n", collection_name);
} else {
const bson_t * item;
uint32_t length;
bson_iter_t iter;
const char * value;
while(mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "value") && BSON_ITER_HOLDS_UTF8(&iter)) {
value = bson_iter_utf8(&iter, &length);
add_ip_list_range(value, list);
}
}
mongoc_cursor_destroy(cursor);
ret = 0;
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
return ret;
}
static void mongo_reread_realms(secrets_list_t * realms_list) {
UNUSED_ARG(realms_list);
mongoc_collection_t * collection = mongo_get_collection("realm");
if(!collection)
return;
bson_t query;
bson_init(&query);
bson_t fields;
bson_init(&fields);
BSON_APPEND_INT32(&fields, "realm", 1);
BSON_APPEND_INT32(&fields, "origin", 1);
BSON_APPEND_INT32(&fields, "options", 1);
mongoc_cursor_t * cursor;
cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, 0, 0, 0, &query, &fields, NULL);
if (!cursor) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error querying MongoDB collection 'realm'\n");
} else {
ur_string_map *o_to_realm_new = ur_string_map_create(free);
const bson_t * item;
uint32_t length;
bson_iter_t iter;
while (mongoc_cursor_next(cursor, &item)) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
char * _realm = strdup(bson_iter_utf8(&iter, &length));
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "origin") && BSON_ITER_HOLDS_ARRAY(&iter)) {
const uint8_t *docbuf = NULL;
uint32_t doclen = 0;
bson_t origin_array;
bson_iter_t origin_iter;
bson_iter_array(&iter, &doclen, &docbuf);
bson_init_static(&origin_array, docbuf, doclen);
if (bson_iter_init(&origin_iter, &origin_array)) {
while(bson_iter_next(&origin_iter)) {
if (BSON_ITER_HOLDS_UTF8(&origin_iter)) {
const char * _origin = bson_iter_utf8(&origin_iter, &length);
ur_string_map_value_type value = strdup(_origin);
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type)_realm, value);
}
}
}
}
realm_params_t* rp = get_realm(_realm);
lock_realms();
rp->options.perf_options.max_bps = turn_params.max_bps;
rp->options.perf_options.total_quota = turn_params.total_quota;
rp->options.perf_options.user_quota = turn_params.user_quota;
unlock_realms();
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "options") && BSON_ITER_HOLDS_DOCUMENT(&iter)) {
const uint8_t *docbuf = NULL;
uint32_t doclen = 0;
bson_t options;
bson_iter_t options_iter;
bson_iter_document(&iter, &doclen, &docbuf);
bson_init_static(&options, docbuf, doclen);
if (bson_iter_init(&options_iter, &options)) {
while(bson_iter_next(&options_iter)) {
const char * _k = bson_iter_key(&options_iter);
int32_t _v;
if (BSON_ITER_HOLDS_DOUBLE(&options_iter)) {
_v = (int32_t)bson_iter_double(&options_iter);
} else if (BSON_ITER_HOLDS_INT32(&options_iter)) {
_v = bson_iter_int32(&options_iter);
} else if (BSON_ITER_HOLDS_INT64(&options_iter)) {
_v = (int32_t)bson_iter_int64(&options_iter);
}
if (_v) {
if(!strcmp(_k,"max-bps"))
rp->options.perf_options.max_bps = (band_limit_t)_v;
else if(!strcmp(_k,"total-quota"))
rp->options.perf_options.total_quota = (vint)_v;
else if(!strcmp(_k,"user-quota"))
rp->options.perf_options.user_quota = (vint)_v;
else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown realm option: %s\n", _k);
}
}
}
}
}
free(_realm);
}
}
update_o_to_realm(o_to_realm_new);
mongoc_cursor_destroy(cursor);
}
mongoc_collection_destroy(collection);
bson_destroy(&query);
bson_destroy(&fields);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static turn_dbdriver_t driver = {
&mongo_get_auth_secrets,
&mongo_get_user_key,
&mongo_get_user_pwd,
&mongo_set_user_key,
&mongo_set_user_pwd,
&mongo_del_user,
&mongo_list_users,
&mongo_show_secret,
&mongo_del_secret,
&mongo_set_secret,
&mongo_add_origin,
&mongo_del_origin,
&mongo_list_origins,
&mongo_set_realm_option_one,
&mongo_list_realm_options,
&mongo_auth_ping,
&mongo_get_ip_list,
&mongo_reread_realms
};
turn_dbdriver_t * get_mongo_dbdriver(void) {
return &driver;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#else
turn_dbdriver_t * get_mongo_dbdriver(void) {
return NULL;
}
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DBD_MONGODB__
#define __DBD_MONGODB__
#include "dbdriver.h"
#ifdef __cplusplus
extern "C" {
#endif
turn_dbdriver_t * get_mongo_dbdriver(void);
#ifdef __cplusplus
}
#endif
#endif
/// __DBD_MONGODB__///

View File

@ -0,0 +1,870 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "../mainrelay.h"
#include "dbd_mysql.h"
#if !defined(TURN_NO_MYSQL)
#include <mysql.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static int donot_print_connection_success = 0;
struct _Myconninfo {
char *host;
char *dbname;
char *user;
char *password;
unsigned int port;
unsigned int connect_timeout;
};
typedef struct _Myconninfo Myconninfo;
static void MyconninfoFree(Myconninfo *co) {
if(co) {
if(co->host) turn_free(co->host,strlen(co->host)+1);
if(co->dbname) turn_free(co->dbname, strlen(co->dbname)+1);
if(co->user) turn_free(co->user, strlen(co->user)+1);
if(co->password) turn_free(co->password, strlen(co->password)+1);
ns_bzero(co,sizeof(Myconninfo));
}
}
static Myconninfo *MyconninfoParse(char *userdb, char **errmsg) {
Myconninfo *co = (Myconninfo*)turn_malloc(sizeof(Myconninfo));
ns_bzero(co,sizeof(Myconninfo));
if(userdb) {
char *s0=strdup(userdb);
char *s = s0;
while(s && *s) {
while(*s && (*s==' ')) ++s;
char *snext = strstr(s," ");
if(snext) {
*snext = 0;
++snext;
}
char* seq = strstr(s,"=");
if(!seq) {
MyconninfoFree(co);
co = NULL;
if(errmsg) {
*errmsg = strdup(s);
}
break;
}
*seq = 0;
if(!strcmp(s,"host"))
co->host = strdup(seq+1);
else if(!strcmp(s,"ip"))
co->host = strdup(seq+1);
else if(!strcmp(s,"addr"))
co->host = strdup(seq+1);
else if(!strcmp(s,"ipaddr"))
co->host = strdup(seq+1);
else if(!strcmp(s,"hostaddr"))
co->host = strdup(seq+1);
else if(!strcmp(s,"dbname"))
co->dbname = strdup(seq+1);
else if(!strcmp(s,"db"))
co->dbname = strdup(seq+1);
else if(!strcmp(s,"database"))
co->dbname = strdup(seq+1);
else if(!strcmp(s,"user"))
co->user = strdup(seq+1);
else if(!strcmp(s,"uname"))
co->user = strdup(seq+1);
else if(!strcmp(s,"name"))
co->user = strdup(seq+1);
else if(!strcmp(s,"username"))
co->user = strdup(seq+1);
else if(!strcmp(s,"password"))
co->password = strdup(seq+1);
else if(!strcmp(s,"pwd"))
co->password = strdup(seq+1);
else if(!strcmp(s,"passwd"))
co->password = strdup(seq+1);
else if(!strcmp(s,"secret"))
co->password = strdup(seq+1);
else if(!strcmp(s,"port"))
co->port = (unsigned int)atoi(seq+1);
else if(!strcmp(s,"p"))
co->port = (unsigned int)atoi(seq+1);
else if(!strcmp(s,"connect_timeout"))
co->connect_timeout = (unsigned int)atoi(seq+1);
else if(!strcmp(s,"timeout"))
co->connect_timeout = (unsigned int)atoi(seq+1);
else {
MyconninfoFree(co);
co = NULL;
if(errmsg) {
*errmsg = strdup(s);
}
break;
}
s = snext;
}
turn_free(s0, strlen(s0)+1);
}
if(!(co->dbname))
co->dbname=strdup("0");
if(!(co->host))
co->host=strdup("127.0.0.1");
if(!(co->user))
co->user=strdup("");
if(!(co->password))
co->password=strdup("");
return co;
}
static MYSQL *get_mydb_connection(void) {
persistent_users_db_t *pud = get_persistent_users_db();
MYSQL *mydbconnection = (MYSQL*)(pud->connection);
if(mydbconnection) {
if(mysql_ping(mydbconnection)) {
mysql_close(mydbconnection);
mydbconnection=NULL;
}
}
if(!mydbconnection) {
char *errmsg=NULL;
Myconninfo *co=MyconninfoParse(pud->userdb, &errmsg);
if(!co) {
if(errmsg) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open MySQL DB connection <%s>, connection string format error: %s\n",pud->userdb,errmsg);
turn_free(errmsg,strlen(errmsg)+1);
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open MySQL DB connection <%s>, connection string format error\n",pud->userdb);
}
} else if(errmsg) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open MySQL DB connection <%s>, connection string format error: %s\n",pud->userdb,errmsg);
turn_free(errmsg,strlen(errmsg)+1);
MyconninfoFree(co);
} else if(!(co->dbname)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "MySQL Database name is not provided: <%s>\n",pud->userdb);
MyconninfoFree(co);
} else {
mydbconnection = mysql_init(NULL);
if(!mydbconnection) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot initialize MySQL DB connection\n");
} else {
if(co->connect_timeout)
mysql_options(mydbconnection,MYSQL_OPT_CONNECT_TIMEOUT,&(co->connect_timeout));
MYSQL *conn = mysql_real_connect(mydbconnection, co->host, co->user, co->password, co->dbname, co->port, NULL, CLIENT_IGNORE_SIGPIPE);
if(!conn) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open MySQL DB connection: <%s>, runtime error\n",pud->userdb);
mysql_close(mydbconnection);
mydbconnection=NULL;
} else if(mysql_select_db(mydbconnection, co->dbname)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot connect to MySQL DB: %s\n",co->dbname);
mysql_close(mydbconnection);
mydbconnection=NULL;
} else if(!donot_print_connection_success) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MySQL DB connection success: %s\n",pud->userdb);
}
}
MyconninfoFree(co);
}
pud->connection = mydbconnection;
}
return mydbconnection;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static int mysql_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
int ret = -1;
MYSQL * myc = get_mydb_connection();
if(myc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)==1) {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
size_t sz = lengths[0];
char auth_secret[TURN_LONG_STRING_SIZE];
ns_bcopy(row[0],auth_secret,sz);
auth_secret[sz]=0;
add_to_secrets_list(sl,auth_secret);
}
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
int ret = -1;
MYSQL * myc = get_mydb_connection();
if(myc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select hmackey from turnusers_lt where name='%s' and realm='%s'",usname,realm);
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
MYSQL_ROW row = mysql_fetch_row(mres);
if(row && row[0]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
size_t sz = get_hmackey_size(turn_params.shatype)*2;
if(lengths[0]<sz) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key format: string length=%d (must be %d): user %s\n",(int)lengths[0],(int)sz,usname);
} else {
char kval[sizeof(hmackey_t)+sizeof(hmackey_t)+1];
ns_bcopy(row[0],kval,sz);
kval[sz]=0;
if(convert_string_key_to_binary(kval, key, sz/2)<0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n",kval,usname);
} else {
ret = 0;
}
}
}
}
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_get_user_pwd(u08bits *usname, st_password_t pwd) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select password from turnusers_st where name='%s'",usname);
MYSQL * myc = get_mydb_connection();
if(myc) {
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
MYSQL_ROW row = mysql_fetch_row(mres);
if(row && row[0]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
if(lengths[0]<1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password data for user %s, size in MySQL DB is zero(0)\n",usname);
} else {
ns_bcopy(row[0],pwd,lengths[0]);
pwd[lengths[0]]=0;
ret = 0;
}
}
}
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
snprintf(statement,sizeof(statement),"insert into turnusers_lt (realm,name,hmackey) values('%s','%s','%s')",realm,usname,key);
int res = mysql_query(myc, statement);
if(res) {
snprintf(statement,sizeof(statement),"update turnusers_lt set hmackey='%s' where name='%s' and realm='%s'",key,usname,realm);
res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user key information: %s\n",mysql_error(myc));
}
}
}
return ret;
}
static int mysql_set_user_pwd(u08bits *usname, st_password_t pwd) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
snprintf(statement,sizeof(statement),"insert into turnusers_st values('%s','%s')",usname,pwd);
int res = mysql_query(myc, statement);
if(res) {
snprintf(statement,sizeof(statement),"update turnusers_st set password='%s' where name='%s'",pwd,usname);
res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user key information: %s\n",mysql_error(myc));
} else {
ret = 0;
}
}
}
return ret;
}
static int mysql_del_user(u08bits *usname, int is_st, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
if(is_st) {
snprintf(statement,sizeof(statement),"delete from turnusers_st where name='%s'",usname);
} else {
snprintf(statement,sizeof(statement),"delete from turnusers_lt where name='%s' and realm='%s'",usname,realm);
}
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting user key information: %s\n",mysql_error(myc));
} else {
ret = 0;
}
}
return ret;
}
static int mysql_list_users(int is_st, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
if(is_st) {
snprintf(statement,sizeof(statement),"select name from turnusers_st order by name");
} else if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select name from turnusers_lt where realm='%s' order by name",realm);
} else {
snprintf(statement,sizeof(statement),"select name from turnusers_lt order by name");
}
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0]) {
printf("%s\n",row[0]);
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_show_secret(u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
donot_print_connection_success=1;
MYSQL * myc = get_mydb_connection();
if(myc) {
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=1) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0]) {
printf("%s\n",row[0]);
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_del_secret(u08bits *secret, u08bits *realm) {
int ret = 1;
donot_print_connection_success=1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if (myc) {
if(!secret || (secret[0]==0))
snprintf(statement,sizeof(statement),"delete from turn_secret where realm='%s'",realm);
else
snprintf(statement,sizeof(statement),"delete from turn_secret where value='%s' and realm='%s'",secret,realm);
mysql_query(myc, statement);
ret = 0;
}
return ret;
}
static int mysql_set_secret(u08bits *secret, u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if (myc) {
snprintf(statement,sizeof(statement),"insert into turn_secret (realm,value) values('%s','%s')",realm,secret);
int res = mysql_query(myc, statement);
if (res) {
TURN_LOG_FUNC(
TURN_LOG_LEVEL_ERROR,
"Error inserting/updating secret key information: %s\n",
mysql_error(myc));
} else {
ret = 0;
}
}
return ret;
}
static int mysql_add_origin(u08bits *origin, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if (myc) {
snprintf(statement,sizeof(statement),"insert into turn_origin_to_realm (origin,realm) values('%s','%s')",origin,realm);
int res = mysql_query(myc, statement);
if (res) {
TURN_LOG_FUNC(
TURN_LOG_LEVEL_ERROR,
"Error inserting origin information: %s\n",
mysql_error(myc));
} else {
ret = 0;
}
}
return ret;
}
static int mysql_del_origin(u08bits *origin) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if (myc) {
snprintf(statement,sizeof(statement),"delete from turn_origin_to_realm where origin='%s'",origin);
int res = mysql_query(myc, statement);
if (res) {
TURN_LOG_FUNC(
TURN_LOG_LEVEL_ERROR,
"Error deleting origin information: %s\n",
mysql_error(myc));
} else {
ret = 0;
}
}
return ret;
}
static int mysql_list_origins(u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm where realm='%s' order by origin",realm);
} else {
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm order by origin,realm");
}
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=2) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0] && row[1]) {
printf("%s ==>> %s\n",row[0],row[1]);
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static int mysql_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if (myc) {
{
snprintf(statement,sizeof(statement),"delete from turn_realm_option where realm='%s' and opt='%s'",realm,opt);
mysql_query(myc, statement);
}
if(value>0) {
snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%lu')",realm,opt,(unsigned long)value);
int res = mysql_query(myc, statement);
if (res) {
TURN_LOG_FUNC(
TURN_LOG_LEVEL_ERROR,
"Error inserting realm option information: %s\n",
mysql_error(myc));
} else {
ret = 0;
}
}
}
return ret;
}
static int mysql_list_realm_options(u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option where realm='%s' order by realm,opt",realm);
} else {
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option order by realm,opt");
}
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=3) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0] && row[1] && row[2]) {
printf("%s[%s]=%s\n",row[1],row[0],row[2]);
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static void mysql_auth_ping(void * rch) {
UNUSED_ARG(rch);
donot_print_connection_success = 1;
MYSQL * myc = get_mydb_connection();
if(myc) {
char statement[TURN_LONG_STRING_SIZE];
STRCPY(statement,"select value from turn_secret");
int res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else {
mysql_free_result(mres);
}
}
}
}
static int mysql_get_ip_list(const char *kind, ip_range_list_t * list) {
int ret = 1;
MYSQL * myc = get_mydb_connection();
if(myc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select ip_range from %s_peer_ip",kind);
int res = mysql_query(myc, statement);
if(res == 0) {
MYSQL_RES *mres = mysql_store_result(myc);
if(mres && mysql_field_count(myc)==1) {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
size_t sz = lengths[0];
char kval[TURN_LONG_STRING_SIZE];
ns_bcopy(row[0],kval,sz);
kval[sz]=0;
add_ip_list_range(kval,list);
}
}
}
}
ret = 0;
}
if(mres)
mysql_free_result(mres);
}
}
return ret;
}
static void mysql_reread_realms(secrets_list_t * realms_list) {
MYSQL * myc = get_mydb_connection();
if(myc) {
char statement[TURN_LONG_STRING_SIZE];
{
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm");
int res = mysql_query(myc, statement);
if(res == 0) {
MYSQL_RES *mres = mysql_store_result(myc);
if(mres && mysql_field_count(myc)==2) {
ur_string_map *o_to_realm_new = ur_string_map_create(free);
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0] && row[1]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
size_t sz = lengths[0];
char oval[513];
ns_bcopy(row[0],oval,sz);
oval[sz]=0;
char *rval=strdup(row[1]);
get_realm(rval);
ur_string_map_value_type value = strdup(rval);
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) oval, value);
}
}
}
}
update_o_to_realm(o_to_realm_new);
}
if(mres)
mysql_free_result(mres);
}
}
{
size_t i = 0;
size_t rlsz = 0;
lock_realms();
rlsz = realms_list->sz;
unlock_realms();
for (i = 0; i<rlsz; ++i) {
char *realm = realms_list->secrets[i];
realm_params_t* rp = get_realm(realm);
lock_realms();
rp->options.perf_options.max_bps = turn_params.max_bps;
unlock_realms();
lock_realms();
rp->options.perf_options.total_quota = turn_params.total_quota;
unlock_realms();
lock_realms();
rp->options.perf_options.user_quota = turn_params.user_quota;
unlock_realms();
}
}
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option");
int res = mysql_query(myc, statement);
if(res == 0) {
MYSQL_RES *mres = mysql_store_result(myc);
if(mres && mysql_field_count(myc)==3) {
for(;;) {
MYSQL_ROW row = mysql_fetch_row(mres);
if(!row) {
break;
} else {
if(row[0] && row[1] && row[2]) {
unsigned long *lengths = mysql_fetch_lengths(mres);
if(lengths) {
char rval[513];
size_t sz = lengths[0];
ns_bcopy(row[0],rval,sz);
rval[sz]=0;
char oval[513];
sz = lengths[1];
ns_bcopy(row[1],oval,sz);
oval[sz]=0;
char vval[513];
sz = lengths[2];
ns_bcopy(row[2],vval,sz);
vval[sz]=0;
realm_params_t* rp = get_realm(rval);
if(!strcmp(oval,"max-bps"))
rp->options.perf_options.max_bps = (band_limit_t)atol(vval);
else if(!strcmp(oval,"total-quota"))
rp->options.perf_options.total_quota = (vint)atoi(vval);
else if(!strcmp(oval,"user-quota"))
rp->options.perf_options.user_quota = (vint)atoi(vval);
else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown realm option: %s\n", oval);
}
}
}
}
}
}
if(mres)
mysql_free_result(mres);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static turn_dbdriver_t driver = {
&mysql_get_auth_secrets,
&mysql_get_user_key,
&mysql_get_user_pwd,
&mysql_set_user_key,
&mysql_set_user_pwd,
&mysql_del_user,
&mysql_list_users,
&mysql_show_secret,
&mysql_del_secret,
&mysql_set_secret,
&mysql_add_origin,
&mysql_del_origin,
&mysql_list_origins,
&mysql_set_realm_option_one,
&mysql_list_realm_options,
&mysql_auth_ping,
&mysql_get_ip_list,
&mysql_reread_realms
};
turn_dbdriver_t * get_mysql_dbdriver(void) {
return &driver;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#else
turn_dbdriver_t * get_mysql_dbdriver(void) {
return NULL;
}
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DBD_MYSQL__
#define __DBD_MYSQL__
#include "dbdriver.h"
#ifdef __cplusplus
extern "C" {
#endif
turn_dbdriver_t * get_mysql_dbdriver(void);
#ifdef __cplusplus
}
#endif
#endif
/// __DBD_MYSQL__///

View File

@ -0,0 +1,668 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "../mainrelay.h"
#include "dbd_pgsql.h"
#if !defined(TURN_NO_PQ)
#include <libpq-fe.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static int donot_print_connection_success = 0;
static PGconn *get_pqdb_connection(void) {
persistent_users_db_t *pud = get_persistent_users_db();
PGconn *pqdbconnection = (PGconn*)(pud->connection);
if(pqdbconnection) {
ConnStatusType status = PQstatus(pqdbconnection);
if(status != CONNECTION_OK) {
PQfinish(pqdbconnection);
pqdbconnection = NULL;
}
}
if(!pqdbconnection) {
char *errmsg=NULL;
PQconninfoOption *co = PQconninfoParse(pud->userdb, &errmsg);
if(!co) {
if(errmsg) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection <%s>, connection string format error: %s\n",pud->userdb,errmsg);
turn_free(errmsg,strlen(errmsg)+1);
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, unknown connection string format error\n",pud->userdb);
}
} else {
PQconninfoFree(co);
if(errmsg)
turn_free(errmsg,strlen(errmsg)+1);
pqdbconnection = PQconnectdb(pud->userdb);
if(!pqdbconnection) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb);
} else {
ConnStatusType status = PQstatus(pqdbconnection);
if(status != CONNECTION_OK) {
PQfinish(pqdbconnection);
pqdbconnection = NULL;
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot open PostgreSQL DB connection: <%s>, runtime error\n",pud->userdb);
} else if(!donot_print_connection_success){
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "PostgreSQL DB connection success: %s\n",pud->userdb);
}
}
}
pud->connection = pqdbconnection;
}
return pqdbconnection;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static int pgsql_get_auth_secrets(secrets_list_t *sl, u08bits *realm) {
int ret = 1;
PGconn * pqc = get_pqdb_connection();
if(pqc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *kval = PQgetvalue(res,i,0);
if(kval) {
add_to_secrets_list(sl,kval);
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_get_user_key(u08bits *usname, u08bits *realm, hmackey_t key) {
int ret = 1;
PGconn * pqc = get_pqdb_connection();
if(pqc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select hmackey from turnusers_lt where name='%s' and realm='%s'",usname,realm);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res)!=1)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
char *kval = PQgetvalue(res,0,0);
int len = PQgetlength(res,0,0);
if(kval) {
size_t sz = get_hmackey_size(turn_params.shatype);
if(((size_t)len<sz*2)||(strlen(kval)<sz*2)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key format: %s, user %s\n",kval,usname);
} else if(convert_string_key_to_binary(kval, key, sz)<0) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n",kval,usname);
} else {
ret = 0;
}
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong hmackey data for user %s: NULL\n",usname);
}
}
if(res)
PQclear(res);
}
return ret;
}
static int pgsql_get_user_pwd(u08bits *usname, st_password_t pwd) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select password from turnusers_st where name='%s'",usname);
PGconn * pqc = get_pqdb_connection();
if(pqc) {
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res)!=1)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
char *kval = PQgetvalue(res,0,0);
if(kval) {
strncpy((char*)pwd,kval,sizeof(st_password_t));
ret = 0;
} else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong password data for user %s: NULL\n",usname);
}
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_set_user_key(u08bits *usname, u08bits *realm, const char *key) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
snprintf(statement,sizeof(statement),"insert into turnusers_lt (realm,name,hmackey) values('%s','%s','%s')",realm,usname,key);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
if(res) {
PQclear(res);
}
snprintf(statement,sizeof(statement),"update turnusers_lt set hmackey='%s' where name='%s' and realm='%s'",key,usname,realm);
res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user information: %s\n",PQerrorMessage(pqc));
} else {
ret = 0;
}
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_set_user_pwd(u08bits *usname, st_password_t pwd) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
snprintf(statement,sizeof(statement),"insert into turnusers_st values('%s','%s')",usname,pwd);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
if(res) {
PQclear(res);
}
snprintf(statement,sizeof(statement),"update turnusers_st set password='%s' where name='%s'",pwd,usname);
res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating user information: %s\n",PQerrorMessage(pqc));
} else {
ret = 0;
}
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_del_user(u08bits *usname, int is_st, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
if(is_st) {
snprintf(statement,sizeof(statement),"delete from turnusers_st where name='%s'",usname);
} else {
snprintf(statement,sizeof(statement),"delete from turnusers_lt where name='%s' and realm='%s'",usname,realm);
}
PGresult *res = PQexec(pqc, statement);
if(res) {
PQclear(res);
ret = 0;
}
}
return ret;
}
static int pgsql_list_users(int is_st, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
if(is_st) {
snprintf(statement,sizeof(statement),"select name from turnusers_st order by name");
} else if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select name from turnusers_lt where realm='%s' order by name",realm);
} else {
snprintf(statement,sizeof(statement),"select name from turnusers_lt order by name");
}
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *kval = PQgetvalue(res,i,0);
if(kval) {
printf("%s\n",kval);
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_show_secret(u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement)-1,"select value from turn_secret where realm='%s'",realm);
donot_print_connection_success=1;
PGconn *pqc = get_pqdb_connection();
if(pqc) {
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *kval = PQgetvalue(res,i,0);
if(kval) {
printf("%s\n",kval);
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_del_secret(u08bits *secret, u08bits *realm) {
int ret = 1;
donot_print_connection_success=1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if (pqc) {
if(!secret || (secret[0]==0))
snprintf(statement,sizeof(statement),"delete from turn_secret where realm='%s'",realm);
else
snprintf(statement,sizeof(statement),"delete from turn_secret where value='%s' and realm='%s'",secret,realm);
PGresult *res = PQexec(pqc, statement);
if (res) {
PQclear(res);
ret = 0;
}
}
return ret;
}
static int pgsql_set_secret(u08bits *secret, u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if (pqc) {
snprintf(statement,sizeof(statement),"insert into turn_secret (realm,value) values('%s','%s')",realm,secret);
PGresult *res = PQexec(pqc, statement);
if (!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(
TURN_LOG_LEVEL_ERROR,
"Error inserting/updating secret key information: %s\n",
PQerrorMessage(pqc));
} else {
ret = 0;
}
if (res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_add_origin(u08bits *origin, u08bits *realm) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
snprintf(statement,sizeof(statement),"insert into turn_origin_to_realm (origin,realm) values('%s','%s')",origin,realm);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting origin information: %s\n",PQerrorMessage(pqc));
} else {
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_del_origin(u08bits *origin) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
snprintf(statement,sizeof(statement),"delete from turn_origin_to_realm where origin='%s'",origin);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error deleting origin information: %s\n",PQerrorMessage(pqc));
} else {
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_list_origins(u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm where realm='%s' order by origin",realm);
} else {
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm order by origin,realm");
}
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *oval = PQgetvalue(res,i,0);
if(oval) {
char *rval = PQgetvalue(res,i,1);
if(rval) {
printf("%s ==>> %s\n",oval,rval);
}
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static int pgsql_set_realm_option_one(u08bits *realm, unsigned long value, const char* opt) {
int ret = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
{
snprintf(statement,sizeof(statement),"delete from turn_realm_option where realm='%s' and opt='%s'",realm,opt);
PGresult *res = PQexec(pqc, statement);
if(res) {
PQclear(res);
}
}
if(value>0) {
snprintf(statement,sizeof(statement),"insert into turn_realm_option (realm,opt,value) values('%s','%s','%lu')",realm,opt,(unsigned long)value);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting realm option information: %s\n",PQerrorMessage(pqc));
} else {
ret = 0;
}
if(res) {
PQclear(res);
}
}
}
return ret;
}
static int pgsql_list_realm_options(u08bits *realm) {
int ret = 1;
donot_print_connection_success = 1;
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
if(realm && realm[0]) {
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option where realm='%s' order by realm,opt",realm);
} else {
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option order by realm,opt");
}
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
} else {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *rval = PQgetvalue(res,i,0);
if(rval) {
char *oval = PQgetvalue(res,i,1);
if(oval) {
char *vval = PQgetvalue(res,i,2);
if(vval) {
printf("%s[%s]=%s\n",oval,rval,vval);
}
}
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static void pgsql_auth_ping(void * rch) {
UNUSED_ARG(rch);
donot_print_connection_success = 1;
PGconn * pqc = get_pqdb_connection();
if(pqc) {
char statement[TURN_LONG_STRING_SIZE];
STRCPY(statement,"select value from turn_secret");
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_TUPLES_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving PostgreSQL DB information: %s\n",PQerrorMessage(pqc));
}
if(res) {
PQclear(res);
}
}
}
static int pgsql_get_ip_list(const char *kind, ip_range_list_t * list) {
int ret = 1;
PGconn * pqc = get_pqdb_connection();
if(pqc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select ip_range from %s_peer_ip",kind);
PGresult *res = PQexec(pqc, statement);
if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *kval = PQgetvalue(res,i,0);
if(kval) {
add_ip_list_range(kval,list);
}
}
ret = 0;
}
if(res) {
PQclear(res);
}
}
return ret;
}
static void pgsql_reread_realms(secrets_list_t * realms_list) {
PGconn * pqc = get_pqdb_connection();
if(pqc) {
char statement[TURN_LONG_STRING_SIZE];
{
snprintf(statement,sizeof(statement),"select origin,realm from turn_origin_to_realm");
PGresult *res = PQexec(pqc, statement);
if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
ur_string_map *o_to_realm_new = ur_string_map_create(free);
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *oval = PQgetvalue(res,i,0);
if(oval) {
char *rval = PQgetvalue(res,i,1);
if(rval) {
get_realm(rval);
ur_string_map_value_type value = strdup(rval);
ur_string_map_put(o_to_realm_new, (const ur_string_map_key_type) oval, value);
}
}
}
update_o_to_realm(o_to_realm_new);
}
if(res) {
PQclear(res);
}
}
{
{
size_t i = 0;
size_t rlsz = 0;
lock_realms();
rlsz = realms_list->sz;
unlock_realms();
for (i = 0; i<rlsz; ++i) {
char *realm = realms_list->secrets[i];
realm_params_t* rp = get_realm(realm);
lock_realms();
rp->options.perf_options.max_bps = turn_params.max_bps;
unlock_realms();
lock_realms();
rp->options.perf_options.total_quota = turn_params.total_quota;
unlock_realms();
lock_realms();
rp->options.perf_options.user_quota = turn_params.user_quota;
unlock_realms();
}
}
snprintf(statement,sizeof(statement),"select realm,opt,value from turn_realm_option");
PGresult *res = PQexec(pqc, statement);
if(res && (PQresultStatus(res) == PGRES_TUPLES_OK)) {
int i = 0;
for(i=0;i<PQntuples(res);i++) {
char *rval = PQgetvalue(res,i,0);
char *oval = PQgetvalue(res,i,1);
char *vval = PQgetvalue(res,i,2);
if(rval && oval && vval) {
realm_params_t* rp = get_realm(rval);
if(!strcmp(oval,"max-bps"))
rp->options.perf_options.max_bps = (band_limit_t)atol(vval);
else if(!strcmp(oval,"total-quota"))
rp->options.perf_options.total_quota = (vint)atoi(vval);
else if(!strcmp(oval,"user-quota"))
rp->options.perf_options.user_quota = (vint)atoi(vval);
else {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown realm option: %s\n", oval);
}
}
}
}
if(res) {
PQclear(res);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
static turn_dbdriver_t driver = {
&pgsql_get_auth_secrets,
&pgsql_get_user_key,
&pgsql_get_user_pwd,
&pgsql_set_user_key,
&pgsql_set_user_pwd,
&pgsql_del_user,
&pgsql_list_users,
&pgsql_show_secret,
&pgsql_del_secret,
&pgsql_set_secret,
&pgsql_add_origin,
&pgsql_del_origin,
&pgsql_list_origins,
&pgsql_set_realm_option_one,
&pgsql_list_realm_options,
&pgsql_auth_ping,
&pgsql_get_ip_list,
&pgsql_reread_realms
};
turn_dbdriver_t * get_pgsql_dbdriver(void) {
return &driver;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#else
turn_dbdriver_t * get_pgsql_dbdriver(void) {
return NULL;
}
#endif

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DBD_POSTGRESQL__
#define __DBD_POSTGRESQL__
#include "dbdriver.h"
#ifdef __cplusplus
extern "C" {
#endif
turn_dbdriver_t * get_pgsql_dbdriver(void);
#ifdef __cplusplus
}
#endif
#endif
/// __DBD_POSTGRESQL__///

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DBD_REDIS__
#define __DBD_REDIS__
#include "dbdriver.h"
#ifdef __cplusplus
extern "C" {
#endif
turn_dbdriver_t * get_redis_dbdriver(void);
#ifdef __cplusplus
}
#endif
#endif
/// __DBD_REDIS__///

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "../mainrelay.h"
#include "dbdriver.h"
#include "dbd_pgsql.h"
#include "dbd_mysql.h"
#include "dbd_mongo.h"
#include "dbd_redis.h"
static turn_dbdriver_t * _driver;
int convert_string_key_to_binary(char* keysource, hmackey_t key, size_t sz) {
char is[3];
size_t i;
unsigned int v;
is[2]=0;
for(i=0;i<sz;i++) {
is[0]=keysource[i*2];
is[1]=keysource[i*2+1];
sscanf(is,"%02x",&v);
key[i]=(unsigned char)v;
}
return 0;
}
persistent_users_db_t * get_persistent_users_db(void) {
return &(turn_params.default_users_db.persistent_users_db);
}
turn_dbdriver_t * get_dbdriver() {
if (!_driver) {
switch(turn_params.default_users_db.userdb_type) {
#if !defined(TURN_NO_PQ)
case TURN_USERDB_TYPE_PQ:
_driver = get_pgsql_dbdriver();
break;
#endif
#if !defined(TURN_NO_MYSQL)
case TURN_USERDB_TYPE_MYSQL:
_driver = get_mysql_dbdriver();
break;
#endif
#if !defined(TURN_NO_MONGO)
case TURN_USERDB_TYPE_MONGO:
_driver = get_mongo_dbdriver();
break;
#endif
#if !defined(TURN_NO_HIREDIS)
case TURN_USERDB_TYPE_REDIS:
_driver = get_redis_dbdriver();
break;
#endif
default:
break;
}
}
return _driver;
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2011, 2012, 2013 Citrix Systems
* Copyright (C) 2014 Vivocha S.p.A.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __DBDRIVER__
#define __DBDRIVER__
#include "../userdb.h"
#ifdef __cplusplus
extern "C" {
#endif
////////////////////////////////////////////
typedef struct _turn_dbdriver_t {
int (*get_auth_secrets)(secrets_list_t *sl, u08bits *realm);
int (*get_user_key)(u08bits *usname, u08bits *realm, hmackey_t key);
int (*get_user_pwd)(u08bits *usname, st_password_t pwd);
int (*set_user_key)(u08bits *usname, u08bits *realm, const char *key);
int (*set_user_pwd)(u08bits *usname, st_password_t pwd);
int (*del_user)(u08bits *usname, int is_st, u08bits *realm);
int (*list_users)(int is_st, u08bits *realm);
int (*show_secret)(u08bits *realm);
int (*del_secret)(u08bits *secret, u08bits *realm);
int (*set_secret)(u08bits *secret, u08bits *realm);
int (*add_origin)(u08bits *origin, u08bits *realm);
int (*del_origin)(u08bits *origin);
int (*list_origins)(u08bits *realm);
int (*set_realm_option_one)(u08bits *realm, unsigned long value, const char* opt);
int (*list_realm_options)(u08bits *realm);
void (*auth_ping)(void * rch);
int (*get_ip_list)(const char *kind, ip_range_list_t * list);
void (*reread_realms)(secrets_list_t * realms_list);
} turn_dbdriver_t;
/////////// USER DB CHECK //////////////////
int convert_string_key_to_binary(char* keysource, hmackey_t key, size_t sz);
persistent_users_db_t * get_persistent_users_db(void);
turn_dbdriver_t * get_dbdriver(void);
////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
/// __DBDRIVER__///

View File

@ -427,6 +427,11 @@ static char Usage[] = "Usage: turnserver [options]\n"
" \"host=<ip-addr> dbname=<database-name> user=<database-user> \\\n password=<database-user-password> port=<db-port> connect_timeout=<seconds>\".\n" " \"host=<ip-addr> dbname=<database-name> user=<database-user> \\\n password=<database-user-password> port=<db-port> connect_timeout=<seconds>\".\n"
" All parameters are optional.\n" " All parameters are optional.\n"
#endif #endif
#if !defined(TURN_NO_MONGO)
" -J, --mongo-userdb <connection-string> MongoDB connection string, if used (default - empty, no MongoDB used).\n"
" This database can be used for long-term and short-term credentials mechanisms,\n"
" and it can store the secret value(s) for secret-based timed authentication in TURN RESP API.\n"
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
" -N, --redis-userdb <connection-string> Redis user database connection string, if used (default - empty, no Redis DB used).\n" " -N, --redis-userdb <connection-string> Redis user database connection string, if used (default - empty, no Redis DB used).\n"
" This database can be used for long-term and short-term credentials mechanisms,\n" " This database can be used for long-term and short-term credentials mechanisms,\n"
@ -557,7 +562,7 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
" -D, --delete-st delete a short-term mechanism user\n" " -D, --delete-st delete a short-term mechanism user\n"
" -l, --list list all long-term mechanism users\n" " -l, --list list all long-term mechanism users\n"
" -L, --list-st list all short-term mechanism users\n" " -L, --list-st list all short-term mechanism users\n"
#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
" -s, --set-secret=<value> Add shared secret for TURN RESP API\n" " -s, --set-secret=<value> Add shared secret for TURN RESP API\n"
" -S, --show-secret Show stored shared secrets for TURN REST API\n" " -S, --show-secret Show stored shared secrets for TURN REST API\n"
" -X, --delete-secret=<value> Delete a shared secret\n" " -X, --delete-secret=<value> Delete a shared secret\n"
@ -576,13 +581,16 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
#if !defined(TURN_NO_MYSQL) #if !defined(TURN_NO_MYSQL)
" -M, --mysql-userdb MySQL user database connection string, if MySQL DB is used.\n" " -M, --mysql-userdb MySQL user database connection string, if MySQL DB is used.\n"
#endif #endif
#if !defined(TURN_NO_MONGO)
" -J, --mongo-userdb MongoDB user database connection string, if MongoDB is used.\n"
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
" -N, --redis-userdb Redis user database connection string, if Redis DB is used.\n" " -N, --redis-userdb Redis user database connection string, if Redis DB is used.\n"
#endif #endif
" -u, --user Username\n" " -u, --user Username\n"
" -r, --realm Realm for long-term mechanism only\n" " -r, --realm Realm for long-term mechanism only\n"
" -p, --password Password\n" " -p, --password Password\n"
#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
" -o, --origin Origin\n" " -o, --origin Origin\n"
#endif #endif
" -H, --sha256 Use SHA256 digest function to be used for the message integrity.\n" " -H, --sha256 Use SHA256 digest function to be used for the message integrity.\n"
@ -595,9 +603,9 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
" Setting to zero value means removal of the option.\n" " Setting to zero value means removal of the option.\n"
" -h, --help Help\n"; " -h, --help Help\n";
#define OPTIONS "c:d:p:L:E:X:i:m:l:r:u:b:B:e:M:N:O:q:Q:s:C:vVofhznaAS" #define OPTIONS "c:d:p:L:E:X:i:m:l:r:u:b:B:e:M:J:N:O:q:Q:s:C:vVofhznaAS"
#define ADMIN_OPTIONS "gGORIHlLkaADSdb:e:M:N:u:r:p:s:X:o:h" #define ADMIN_OPTIONS "gGORIHlLkaADSdb:e:M:J:N:u:r:p:s:X:o:h"
enum EXTRA_OPTS { enum EXTRA_OPTS {
NO_UDP_OPT=256, NO_UDP_OPT=256,
@ -701,6 +709,9 @@ static const struct myoption long_options[] = {
#if !defined(TURN_NO_MYSQL) #if !defined(TURN_NO_MYSQL)
{ "mysql-userdb", required_argument, NULL, 'M' }, { "mysql-userdb", required_argument, NULL, 'M' },
#endif #endif
#if !defined(TURN_NO_MONGO)
{ "mongo-userdb", required_argument, NULL, 'J' },
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
{ "redis-userdb", required_argument, NULL, 'N' }, { "redis-userdb", required_argument, NULL, 'N' },
{ "redis-statsdb", required_argument, NULL, 'O' }, { "redis-statsdb", required_argument, NULL, 'O' },
@ -776,7 +787,7 @@ static const struct myoption admin_long_options[] = {
{ "delete", no_argument, NULL, 'd' }, { "delete", no_argument, NULL, 'd' },
{ "list", no_argument, NULL, 'l' }, { "list", no_argument, NULL, 'l' },
{ "list-st", no_argument, NULL, 'L' }, { "list-st", no_argument, NULL, 'L' },
#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
{ "set-secret", required_argument, NULL, 's' }, { "set-secret", required_argument, NULL, 's' },
{ "show-secret", no_argument, NULL, 'S' }, { "show-secret", no_argument, NULL, 'S' },
{ "delete-secret", required_argument, NULL, 'X' }, { "delete-secret", required_argument, NULL, 'X' },
@ -792,6 +803,9 @@ static const struct myoption admin_long_options[] = {
#if !defined(TURN_NO_MYSQL) #if !defined(TURN_NO_MYSQL)
{ "mysql-userdb", required_argument, NULL, 'M' }, { "mysql-userdb", required_argument, NULL, 'M' },
#endif #endif
#if !defined(TURN_NO_MONGO)
{ "mongo-userdb", required_argument, NULL, 'J' },
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
{ "redis-userdb", required_argument, NULL, 'N' }, { "redis-userdb", required_argument, NULL, 'N' },
#endif #endif
@ -799,7 +813,7 @@ static const struct myoption admin_long_options[] = {
{ "realm", required_argument, NULL, 'r' }, { "realm", required_argument, NULL, 'r' },
{ "password", required_argument, NULL, 'p' }, { "password", required_argument, NULL, 'p' },
{ "sha256", no_argument, NULL, 'H' }, { "sha256", no_argument, NULL, 'H' },
#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
{ "add-origin", no_argument, NULL, 'O' }, { "add-origin", no_argument, NULL, 'O' },
{ "del-origin", no_argument, NULL, 'R' }, { "del-origin", no_argument, NULL, 'R' },
{ "list-origins", required_argument, NULL, 'I' }, { "list-origins", required_argument, NULL, 'I' },
@ -1086,6 +1100,12 @@ static void set_option(int c, char *value)
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL; turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
break; break;
#endif #endif
#if !defined(TURN_NO_MONGO)
case 'J':
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
break;
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
case 'N': case 'N':
STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value); STRCPY(turn_params.default_users_db.persistent_users_db.userdb, value);
@ -1411,7 +1431,7 @@ static int adminmain(int argc, char **argv)
ct = TA_LIST_USERS; ct = TA_LIST_USERS;
is_st = 1; is_st = 1;
break; break;
#if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_PQ) || !defined(TURN_NO_MYSQL) || !defined(TURN_NO_MONGO) || !defined(TURN_NO_HIREDIS)
case 's': case 's':
ct = TA_SET_SECRET; ct = TA_SET_SECRET;
STRCPY(secret,optarg); STRCPY(secret,optarg);
@ -1444,6 +1464,12 @@ static int adminmain(int argc, char **argv)
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL; turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MYSQL;
break; break;
#endif #endif
#if !defined(TURN_NO_MONGO)
case 'J':
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
turn_params.default_users_db.userdb_type = TURN_USERDB_TYPE_MONGO;
break;
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
case 'N': case 'N':
STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg); STRCPY(turn_params.default_users_db.persistent_users_db.userdb,optarg);
@ -1558,6 +1584,12 @@ static void print_features(unsigned long mfn)
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MySQL is not supported\n"); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MySQL is not supported\n");
#endif #endif
#if !defined(TURN_NO_MONGO)
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MongoDB supported\n");
#else
TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "MongoDB is not supported\n");
#endif
#if defined(OPENSSL_THREADS) #if defined(OPENSSL_THREADS)
//TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "OpenSSL multithreading supported\n"); //TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "OpenSSL multithreading supported\n");
#else #else

View File

@ -83,8 +83,6 @@
#include "ns_ioalib_impl.h" #include "ns_ioalib_impl.h"
#include "hiredis_libevent2.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -764,6 +764,11 @@ static void cli_print_configuration(struct cli_session* cs)
cli_print_str(cs,"MySQL/MariaDB","DB type",0); cli_print_str(cs,"MySQL/MariaDB","DB type",0);
break; break;
#endif #endif
#if !defined(TURN_NO_MONGO)
case TURN_USERDB_TYPE_MONGO:
cli_print_str(cs,"MongoDB","DB type",0);
break;
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
case TURN_USERDB_TYPE_REDIS: case TURN_USERDB_TYPE_REDIS:
cli_print_str(cs,"redis","DB type",0); cli_print_str(cs,"redis","DB type",0);

File diff suppressed because it is too large Load Diff

View File

@ -77,6 +77,10 @@ struct _realm_params_t {
}; };
void lock_realms(void);
void unlock_realms(void);
void update_o_to_realm(ur_string_map * o_to_realm_new);
//////////// USER DB ////////////////////////////// //////////// USER DB //////////////////////////////
struct auth_message { struct auth_message {
@ -100,6 +104,9 @@ enum _TURN_USERDB_TYPE {
#if !defined(TURN_NO_MYSQL) #if !defined(TURN_NO_MYSQL)
,TURN_USERDB_TYPE_MYSQL ,TURN_USERDB_TYPE_MYSQL
#endif #endif
#if !defined(TURN_NO_MONGO)
,TURN_USERDB_TYPE_MONGO
#endif
#if !defined(TURN_NO_HIREDIS) #if !defined(TURN_NO_HIREDIS)
,TURN_USERDB_TYPE_REDIS ,TURN_USERDB_TYPE_REDIS
#endif #endif
@ -194,7 +201,7 @@ void reread_realms(void);
int add_user_account(char *user, int dynamic); int add_user_account(char *user, int dynamic);
int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08bits *origin, TURNADMIN_COMMAND_TYPE ct, int is_st, perf_options_t* po); int adminuser(u08bits *user, u08bits *realm, u08bits *pwd, u08bits *secret, u08bits *origin, TURNADMIN_COMMAND_TYPE ct, int is_st, perf_options_t* po);
int add_ip_list_range(char* range, ip_range_list_t * list); int add_ip_list_range(const char* range, ip_range_list_t * list);
///////////// Redis ////////////////////// ///////////// Redis //////////////////////