mirror of
https://github.com/coturn/coturn.git
synced 2025-10-24 04:20:59 +02:00
MongoDB support: initial checkin
This commit is contained in:
parent
48537e9624
commit
5c3b773d9c
67
INSTALL
67
INSTALL
@ -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>"
|
||||
(Linux), "ldconfig -m <libdirname>" (BSD) or "crle -u -l <libdirname>"
|
||||
(Solaris). Your system must be able to find the libevent2, openssl and
|
||||
(optionally) PostgreSQL and/or MySQL (MariaDB) and/or Redis shared libraries,
|
||||
either with the help of the system-wide library search configuration or by
|
||||
using LD_LIBRARY_PATH. "make install" will make a non-garantied effort to add
|
||||
automatically PREFIX/lib and /usr/local/lib to the libraries search path,
|
||||
but if you have some libraries in different non-default directories
|
||||
you will have to add them manually to the search path, or you
|
||||
will have to adjust LD_LIBRARY_PATH.
|
||||
(optionally) PostgreSQL and/or MySQL (MariaDB) and/or MongoDB and/or Redis
|
||||
shared libraries, either with the help of the system-wide library search
|
||||
configuration or by using LD_LIBRARY_PATH. "make install" will make a
|
||||
non-garantied effort to add automatically PREFIX/lib and /usr/local/lib to
|
||||
the libraries search path, but if you have some libraries in different
|
||||
non-default directories you will have to add them manually to the search
|
||||
path, or you will have to adjust LD_LIBRARY_PATH.
|
||||
|
||||
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,
|
||||
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
|
||||
optional, the MySQL (MariaDB) C client development setup is optional, and the
|
||||
Hiredis development files for Redis database access are optional.
|
||||
optional, the MySQL (MariaDB) C client development setup is optional, the MongoDB
|
||||
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
|
||||
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
|
||||
@ -290,6 +290,7 @@ libraries can be downloaded from their web sites:
|
||||
- http://www.libevent.org (required);
|
||||
- http://www.postgresql.org (optional);
|
||||
- http://www.mysql.org (or http://mariadb.org) (optional);
|
||||
- https://github.com/mongodb/mongo-c-driver (optional);
|
||||
- http://redis.io (optional).
|
||||
|
||||
The installations are pretty straightforward - the usual
|
||||
@ -352,6 +353,11 @@ installation:
|
||||
- you have to install gcc first:
|
||||
$ 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 installation commands. Redis support will not be
|
||||
compiled, unless you install it "manually" before the TURN
|
||||
@ -381,7 +387,7 @@ like this:
|
||||
Dynamic library paths:
|
||||
|
||||
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
|
||||
system-wide shared library search path by using commands:
|
||||
|
||||
@ -412,17 +418,17 @@ absolute paths or @rpath/... .
|
||||
|
||||
See also the next section.
|
||||
|
||||
NOTE: See "PostgreSQL setup" and "MySQL setup" and "Redis setup" sections
|
||||
below for more database setup information.
|
||||
NOTE: See "PostgreSQL setup" and "MySQL setup" and "MongoDB setup" and
|
||||
"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
|
||||
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
|
||||
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
|
||||
access utilities and runtime libraries. The server packages may
|
||||
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"
|
||||
|
||||
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 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 ninefingers -r north.gov -p youhavetoberealistic
|
||||
|
||||
XV. Performance tuning
|
||||
XVIII. Performance tuning
|
||||
|
||||
This topic is covered in the wiki page:
|
||||
|
||||
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
|
||||
|
||||
Also, check the project from page links to the TURN/WebRTC configuration examples.
|
||||
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,
|
||||
to view its state, to gather some statistical information, and to make some changes
|
||||
|
||||
@ -27,8 +27,11 @@ IMPL_DEPS = ${COMMON_DEPS} ${IMPL_HEADERS} ${IMPL_MODS}
|
||||
HIREDIS_HEADERS = src/apps/common/hiredis_libevent2.h
|
||||
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}
|
||||
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_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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@ -92,6 +92,8 @@ Options with required values:
|
||||
See the --psql-userdb option in the turnserver section.
|
||||
-M, --mysql-userdb MySQL user database connection string.
|
||||
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.
|
||||
See the --redis-userdb option in the turnserver section.
|
||||
-u, --user User name.
|
||||
|
||||
@ -57,7 +57,7 @@ turnserver - a TURN relay server implementation.
|
||||
|
||||
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
|
||||
|
||||
DESCRIPTION
|
||||
@ -113,6 +113,17 @@ User database settings:
|
||||
Also, see http://www.mysql.org or http://mariadb.org
|
||||
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.
|
||||
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.
|
||||
@ -138,9 +149,9 @@ Flags:
|
||||
|
||||
-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
|
||||
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 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.
|
||||
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
|
||||
be also used for publishing and delivering traffic and allocation event notifications.
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
For the status and statistics database, there are two choices:
|
||||
|
||||
56
configure
vendored
56
configure
vendored
@ -13,6 +13,8 @@ cleanup() {
|
||||
rm -rf ${PQ_TMPCPROGB}
|
||||
rm -rf ${MYSQL_TMPCPROGC}
|
||||
rm -rf ${MYSQL_TMPCPROGB}
|
||||
rm -rf ${MONGO_TMPCPROGC}
|
||||
rm -rf ${MONGO_TMPCPROGB}
|
||||
rm -rf ${D_TMPCPROGC}
|
||||
rm -rf ${D_TMPCPROGB}
|
||||
rm -rf ${E_TMPCPROGC}
|
||||
@ -124,6 +126,30 @@ testlibmysql() {
|
||||
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() {
|
||||
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 ?
|
||||
##########################
|
||||
@ -940,6 +979,23 @@ else
|
||||
TURN_NO_MYSQL="-DTURN_NO_MYSQL"
|
||||
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
|
||||
###########################
|
||||
|
||||
@ -161,14 +161,14 @@
|
||||
# Uncomment to use long-term credential mechanism.
|
||||
# By default no credentials mechanism is used (any user allowed).
|
||||
# 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
|
||||
|
||||
# Uncomment to use short-term credential mechanism.
|
||||
# By default no credentials mechanism is used (any user allowed).
|
||||
# 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
|
||||
|
||||
@ -241,7 +241,7 @@
|
||||
# 'Dynamic' user accounts database file name.
|
||||
# Only users for long-term mechanism can be stored in a flat file,
|
||||
# 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,
|
||||
# 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>"
|
||||
|
||||
# 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
|
||||
# as the user database.
|
||||
# This database can be used for long-term and short-term credential mechanisms
|
||||
|
||||
@ -10,7 +10,7 @@ service, you have to:
|
||||
|
||||
b) For user accounts settings, if using the turnserver
|
||||
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,
|
||||
or use /usr/local/share/turnserver/schema.sql as SQL database schema,
|
||||
or use /usr/local/share/turnserver/schema.userdb.redis as Redis
|
||||
|
||||
916
src/apps/relay/dbdrivers/dbd_mongo.c
Normal file
916
src/apps/relay/dbdrivers/dbd_mongo.c
Normal 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
|
||||
49
src/apps/relay/dbdrivers/dbd_mongo.h
Normal file
49
src/apps/relay/dbdrivers/dbd_mongo.h
Normal 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__///
|
||||
|
||||
870
src/apps/relay/dbdrivers/dbd_mysql.c
Normal file
870
src/apps/relay/dbdrivers/dbd_mysql.c
Normal 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
|
||||
49
src/apps/relay/dbdrivers/dbd_mysql.h
Normal file
49
src/apps/relay/dbdrivers/dbd_mysql.h
Normal 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__///
|
||||
|
||||
668
src/apps/relay/dbdrivers/dbd_pgsql.c
Normal file
668
src/apps/relay/dbdrivers/dbd_pgsql.c
Normal 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
|
||||
49
src/apps/relay/dbdrivers/dbd_pgsql.h
Normal file
49
src/apps/relay/dbdrivers/dbd_pgsql.h
Normal 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__///
|
||||
|
||||
1150
src/apps/relay/dbdrivers/dbd_redis.c
Normal file
1150
src/apps/relay/dbdrivers/dbd_redis.c
Normal file
File diff suppressed because it is too large
Load Diff
49
src/apps/relay/dbdrivers/dbd_redis.h
Normal file
49
src/apps/relay/dbdrivers/dbd_redis.h
Normal 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__///
|
||||
|
||||
90
src/apps/relay/dbdrivers/dbdriver.c
Normal file
90
src/apps/relay/dbdrivers/dbdriver.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
78
src/apps/relay/dbdrivers/dbdriver.h
Normal file
78
src/apps/relay/dbdrivers/dbdriver.h
Normal 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__///
|
||||
|
||||
@ -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"
|
||||
" All parameters are optional.\n"
|
||||
#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)
|
||||
" -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"
|
||||
@ -557,7 +562,7 @@ static char AdminUsage[] = "Usage: turnadmin [command] [options]\n"
|
||||
" -D, --delete-st delete a short-term mechanism user\n"
|
||||
" -l, --list list all long-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, --show-secret Show stored shared secrets for TURN REST API\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)
|
||||
" -M, --mysql-userdb MySQL user database connection string, if MySQL DB is used.\n"
|
||||
#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)
|
||||
" -N, --redis-userdb Redis user database connection string, if Redis DB is used.\n"
|
||||
#endif
|
||||
" -u, --user Username\n"
|
||||
" -r, --realm Realm for long-term mechanism only\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"
|
||||
#endif
|
||||
" -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"
|
||||
" -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 ADMIN_OPTIONS "gGORIHlLkaADSdb:e:M:N:u:r:p:s:X:o:h"
|
||||
#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:J:N:u:r:p:s:X:o:h"
|
||||
|
||||
enum EXTRA_OPTS {
|
||||
NO_UDP_OPT=256,
|
||||
@ -701,6 +709,9 @@ static const struct myoption long_options[] = {
|
||||
#if !defined(TURN_NO_MYSQL)
|
||||
{ "mysql-userdb", required_argument, NULL, 'M' },
|
||||
#endif
|
||||
#if !defined(TURN_NO_MONGO)
|
||||
{ "mongo-userdb", required_argument, NULL, 'J' },
|
||||
#endif
|
||||
#if !defined(TURN_NO_HIREDIS)
|
||||
{ "redis-userdb", required_argument, NULL, 'N' },
|
||||
{ "redis-statsdb", required_argument, NULL, 'O' },
|
||||
@ -776,7 +787,7 @@ static const struct myoption admin_long_options[] = {
|
||||
{ "delete", no_argument, NULL, 'd' },
|
||||
{ "list", 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' },
|
||||
{ "show-secret", no_argument, NULL, 'S' },
|
||||
{ "delete-secret", required_argument, NULL, 'X' },
|
||||
@ -792,6 +803,9 @@ static const struct myoption admin_long_options[] = {
|
||||
#if !defined(TURN_NO_MYSQL)
|
||||
{ "mysql-userdb", required_argument, NULL, 'M' },
|
||||
#endif
|
||||
#if !defined(TURN_NO_MONGO)
|
||||
{ "mongo-userdb", required_argument, NULL, 'J' },
|
||||
#endif
|
||||
#if !defined(TURN_NO_HIREDIS)
|
||||
{ "redis-userdb", required_argument, NULL, 'N' },
|
||||
#endif
|
||||
@ -799,7 +813,7 @@ static const struct myoption admin_long_options[] = {
|
||||
{ "realm", required_argument, NULL, 'r' },
|
||||
{ "password", required_argument, NULL, 'p' },
|
||||
{ "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' },
|
||||
{ "del-origin", no_argument, NULL, 'R' },
|
||||
{ "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;
|
||||
break;
|
||||
#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)
|
||||
case 'N':
|
||||
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;
|
||||
is_st = 1;
|
||||
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':
|
||||
ct = TA_SET_SECRET;
|
||||
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;
|
||||
break;
|
||||
#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)
|
||||
case 'N':
|
||||
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");
|
||||
#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)
|
||||
//TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "OpenSSL multithreading supported\n");
|
||||
#else
|
||||
|
||||
@ -83,8 +83,6 @@
|
||||
|
||||
#include "ns_ioalib_impl.h"
|
||||
|
||||
#include "hiredis_libevent2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -764,6 +764,11 @@ static void cli_print_configuration(struct cli_session* cs)
|
||||
cli_print_str(cs,"MySQL/MariaDB","DB type",0);
|
||||
break;
|
||||
#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)
|
||||
case TURN_USERDB_TYPE_REDIS:
|
||||
cli_print_str(cs,"redis","DB type",0);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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 //////////////////////////////
|
||||
|
||||
struct auth_message {
|
||||
@ -100,6 +104,9 @@ enum _TURN_USERDB_TYPE {
|
||||
#if !defined(TURN_NO_MYSQL)
|
||||
,TURN_USERDB_TYPE_MYSQL
|
||||
#endif
|
||||
#if !defined(TURN_NO_MONGO)
|
||||
,TURN_USERDB_TYPE_MONGO
|
||||
#endif
|
||||
#if !defined(TURN_NO_HIREDIS)
|
||||
,TURN_USERDB_TYPE_REDIS
|
||||
#endif
|
||||
@ -194,7 +201,7 @@ void reread_realms(void);
|
||||
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 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 //////////////////////
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user