diff --git a/Makefile.am b/Makefile.am index 78c5b90..2c1d21f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,16 @@ EXTRA_DIST = example-cfg.json -INCLUDES = $(PTHREAD_FLAGS) @SQLITE3_CFLAGS@ @MYSQL_CFLAGS@ -fno-strict-aliasing +INCLUDES = -fno-strict-aliasing $(PTHREAD_FLAGS) @SQLITE3_CFLAGS@ \ + @MYSQL_CFLAGS@ @POSTGRESQL_CFLAGS@ bin_PROGRAMS = pushpoold pushpoold_SOURCES = anet.h elist.h htab.h protocol.h server.h ubbp.h \ hist.c htab.c anet.c config.c msg.c server.c util.c \ - db-sqlite.c db-mysql.c -pushpoold_LDFLAGS = $(PTHREAD_FLAGS) + db-sqlite.c db-mysql.c db-postgresql.c +pushpoold_LDFLAGS = $(PTHREAD_FLAGS) @SQLITE3_LDFLAGS@ \ + @MYSQL_LDFLAGS@ @POSTGRESQL_LDFLAGS@ pushpoold_LDADD = @LIBCURL@ @EVENT_LIBS@ @PTHREAD_LIBS@ @JANSSON_LIBS@ \ - @CRYPTO_LIBS@ @Z_LIBS@ @SQLITE3_LDFLAGS@ \ - @MYSQL_LDFLAGS@ + @CRYPTO_LIBS@ @Z_LIBS@ diff --git a/config.c b/config.c index fb3053a..e8f5fb9 100644 --- a/config.c +++ b/config.c @@ -177,6 +177,11 @@ static void parse_database(const json_t *db_obj) } else if (!strcmp(tmp_str, "mysql")) { srv.db_eng = SDB_MYSQL; srv.db_ops = &mysql_db_ops; +#endif +#ifdef HAVE_POSTGRESQL + } else if (!strcmp(tmp_str, "postgresql")) { + srv.db_eng = SDB_POSTGRESQL; + srv.db_ops = &postgresql_db_ops; #endif } else { applog(LOG_ERR, "invalid database.engine"); @@ -213,7 +218,7 @@ static void parse_database(const json_t *db_obj) srv.db_name = strdup(db_name); break; - case SDB_MYSQL: + default: if (!db_host) db_host = "localhost"; if (db_port < 0) diff --git a/configure.ac b/configure.ac index 7d3f9d5..22eea03 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,7 @@ PKG_PROG_PKG_CONFIG() AX_LIB_SQLITE3() AX_LIB_MYSQL() +AX_LIB_POSTGRESQL(7.4.0) LIBCURL_CHECK_CONFIG(, 7.10.1, , [AC_MSG_ERROR([Missing required libcurl >= 7.10.1])]) diff --git a/db-postgresql.c b/db-postgresql.c new file mode 100644 index 0000000..8ddd3a4 --- /dev/null +++ b/db-postgresql.c @@ -0,0 +1,87 @@ + +/* + * Copyright 2011 Shane Wegner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "autotools-config.h" + +#ifdef HAVE_POSTGRESQL + +#include +#include +#include +#include +#include +#include + +#include "server.h" + +static char *pg_pwdb_lookup(const char *user) +{ + char *pw = NULL; + PGresult *res; + const char *paramvalues[] = { user }; + res = + PQexecParams(srv.db_cxn, srv.db_stmt_pwdb, 1, NULL, + paramvalues, NULL, NULL, 0); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + applog(LOG_ERR, "pg_pwdb_lookup query failed: %s", + PQerrorMessage(srv.db_cxn)); + goto out; + } + if (PQnfields(res) != 1 || PQntuples(res) < 1) + goto out; + pw = strdup(PQgetvalue(res, 0, 0)); +out: + PQclear(res); + return pw; +} + +static void pg_close(void) +{ + PQfinish(srv.db_cxn); +} + +static bool pg_open(void) +{ + char *portstr = NULL; + if (srv.db_port > 0) + if (asprintf(&portstr, "%d", srv.db_port) < 0) + return false; + srv.db_cxn = PQsetdbLogin(srv.db_host, portstr, NULL, NULL, + srv.db_name, srv.db_username, + srv.db_password); + free(portstr); + if (PQstatus(srv.db_cxn) != CONNECTION_OK) { + applog(LOG_ERR, "failed to connect to postgresql: %s", + PQerrorMessage(srv.db_cxn)); + pg_close(); + return false; + } + return true; +} + +struct server_db_ops postgresql_db_ops = { + .pwdb_lookup = pg_pwdb_lookup, + .open = pg_open, + .close = pg_close, +}; + +#endif diff --git a/db-sqlite.c b/db-sqlite.c index d540149..bb91be8 100644 --- a/db-sqlite.c +++ b/db-sqlite.c @@ -22,7 +22,7 @@ #endif #include "autotools-config.h" -#ifdef HAVE_SQLITE3 /**/ +#ifdef HAVE_SQLITE3 #include #include @@ -98,4 +98,4 @@ struct server_db_ops sqlite_db_ops = { .close = sql_close, }; -#endif /* HAVE_SQLITE3 /**/ */ +#endif /* HAVE_SQLITE3 */ diff --git a/example-cfg.json b/example-cfg.json index f01d22b..0a6b03e 100644 --- a/example-cfg.json +++ b/example-cfg.json @@ -30,6 +30,21 @@ "stmt.pwdb" : "SELECT password FROM pool_worker WHERE username = '%s'" + + # ... or ... + + "engine" : "postgresql", + + "host" : "db.example.com", + + "port" : 12121, + + "name" : "mydatabasename", + "username" : "myuser", + "password" : "mypass", + + "stmt.pwdb" : + "SELECT password FROM pool_worker WHERE username = $1" }, "pid" : "/tmp/pushpoold.pid", diff --git a/m4/ax_lib_postgresql.m4 b/m4/ax_lib_postgresql.m4 new file mode 100644 index 0000000..327158f --- /dev/null +++ b/m4/ax_lib_postgresql.m4 @@ -0,0 +1,136 @@ +dnl @synopsis AX_LIB_POSTGRESQL([MINIMUM-VERSION]) +dnl +dnl This macro provides tests of availability of PostgreSQL 'libpq' +dnl library of particular version or newer. +dnl +dnl AX_LIB_POSTGRESQL macro takes only one argument which is optional. +dnl If there is no required version passed, then macro does not run +dnl version test. +dnl +dnl The --with-postgresql option takes one of three possible values: +dnl +dnl no - do not check for PostgreSQL client library +dnl +dnl yes - do check for PostgreSQL library in standard locations +dnl (pg_config should be in the PATH) +dnl +dnl path - complete path to pg_config utility, use this option if +dnl pg_config can't be found in the PATH +dnl +dnl This macro calls: +dnl +dnl AC_SUBST(POSTGRESQL_CFLAGS) +dnl AC_SUBST(POSTGRESQL_LDFLAGS) +dnl AC_SUBST(POSTGRESQL_VERSION) +dnl +dnl And sets: +dnl +dnl HAVE_POSTGRESQL +dnl +dnl @category InstalledPackages +dnl @category Cxx +dnl @author Mateusz Loskot +dnl @version 2006-07-16 +dnl @license AllPermissive + +AC_DEFUN([AX_LIB_POSTGRESQL], +[ + AC_ARG_WITH([postgresql], + AC_HELP_STRING([--with-postgresql=@<:@ARG@:>@], + [use PostgreSQL library @<:@default=yes@:>@, optionally specify path to pg_config] + ), + [ + if test "$withval" = "no"; then + want_postgresql="no" + elif test "$withval" = "yes"; then + want_postgresql="yes" + else + want_postgresql="yes" + PG_CONFIG="$withval" + fi + ], + [want_postgresql="yes"] + ) + + POSTGRESQL_CFLAGS="" + POSTGRESQL_LDFLAGS="" + POSTGRESQL_POSTGRESQL="" + + dnl + dnl Check PostgreSQL libraries (libpq) + dnl + + if test "$want_postgresql" = "yes"; then + + if test -z "$PG_CONFIG" -o test; then + AC_PATH_PROG([PG_CONFIG], [pg_config], [no]) + fi + + if test "$PG_CONFIG" != "no"; then + AC_MSG_CHECKING([for PostgreSQL libraries]) + + POSTGRESQL_CFLAGS="-I`$PG_CONFIG --includedir`" + POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir` -lpq" + + POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` + + AC_DEFINE([HAVE_POSTGRESQL], [1], + [Define to 1 if PostgreSQL libraries are available]) + + found_postgresql="yes" + AC_MSG_RESULT([yes]) + else + found_postgresql="no" + AC_MSG_RESULT([no]) + fi + fi + + dnl + dnl Check if required version of PostgreSQL is available + dnl + + + postgresql_version_req=ifelse([$1], [], [], [$1]) + + if test "$found_postgresql" = "yes" -a -n "$postgresql_version_req"; then + + AC_MSG_CHECKING([if PostgreSQL version is >= $postgresql_version_req]) + + dnl Decompose required version string of PostgreSQL + dnl and calculate its number representation + postgresql_version_req_major=`expr $postgresql_version_req : '\([[0-9]]*\)'` + postgresql_version_req_minor=`expr $postgresql_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + postgresql_version_req_micro=`expr $postgresql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$postgresql_version_req_micro" = "x"; then + postgresql_version_req_micro="0" + fi + + postgresql_version_req_number=`expr $postgresql_version_req_major \* 1000000 \ + \+ $postgresql_version_req_minor \* 1000 \ + \+ $postgresql_version_req_micro` + + dnl Decompose version string of installed PostgreSQL + dnl and calculate its number representation + postgresql_version_major=`expr $POSTGRESQL_VERSION : '\([[0-9]]*\)'` + postgresql_version_minor=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'` + postgresql_version_micro=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$postgresql_version_micro" = "x"; then + postgresql_version_micro="0" + fi + + postgresql_version_number=`expr $postgresql_version_major \* 1000000 \ + \+ $postgresql_version_minor \* 1000 \ + \+ $postgresql_version_micro` + + postgresql_version_check=`expr $postgresql_version_number \>\= $postgresql_version_req_number` + if test "$postgresql_version_check" = "1"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + + AC_SUBST([POSTGRESQL_VERSION]) + AC_SUBST([POSTGRESQL_CFLAGS]) + AC_SUBST([POSTGRESQL_LDFLAGS]) +]) diff --git a/server.c b/server.c index c30bc6f..7575ddf 100644 --- a/server.c +++ b/server.c @@ -99,6 +99,9 @@ struct server srv = { #elif defined(HAVE_MYSQL) .db_eng = SDB_MYSQL, .db_ops = &mysql_db_ops, +#elif defined(HAVE_POSTGRESQL) + .db_eng = SDB_POSTGRESQL, + .db_ops = &postgresql_db_ops, #else #error("No valid database engines defined") #endif diff --git a/server.h b/server.h index 43df03c..b2f7096 100644 --- a/server.h +++ b/server.h @@ -20,7 +20,7 @@ * */ -#include +#include "autotools-config.h" #include #include @@ -109,6 +109,7 @@ struct server_db_ops { enum server_db_eng { SDB_SQLITE, SDB_MYSQL, + SDB_POSTGRESQL, }; struct server { @@ -212,11 +213,14 @@ extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); extern unsigned char * g_base64_decode (const char *text, size_t *out_len); /* db-*.c */ -#ifdef HAVE_SQLITE3 /**/ +#ifdef HAVE_SQLITE3 extern struct server_db_ops sqlite_db_ops; #endif #ifdef HAVE_MYSQL extern struct server_db_ops mysql_db_ops; #endif +#ifdef HAVE_POSTGRESQL +extern struct server_db_ops postgresql_db_ops; +#endif #endif /* __SERVER_H__ */