sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit a07cc5b2fd16149b1d023ba479fabe39ae60834e
parent 0df026b55107ae94103641ee726ec9629af4ed4b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 22 Mar 2026 12:02:46 +0100

refactor sync: split up large DB logic into individual files, decentralize PREPARE, remove plugin

Diffstat:
Mconfigure.ac | 2++
Mdebian/libsync-dev.install | 2+-
Msrc/include/Makefile.am | 11++---------
Asrc/include/sync/Makefile.am | 10++++++++++
Asrc/include/sync/sync-database/Makefile.am | 18++++++++++++++++++
Asrc/include/sync/sync-database/common.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/create_tables.h | 34++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/drop_tables.h | 34++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/gc.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/increment_lifetime_TR.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/lookup_account_TR.h | 40++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/lookup_backup_TR.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/lookup_pending_payments_by_account_TR.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/preflight.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/store_backup_TR.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/store_payment_TR.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync-database/update_backup_TR.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/include/sync/sync_database_lib.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/include/sync_service.h -> src/include/sync/sync_service.h | 0
Asrc/include/sync/sync_testing_lib.h | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/include/sync_util.h -> src/include/sync/sync_util.h | 0
Dsrc/include/sync_database_lib.h | 50--------------------------------------------------
Dsrc/include/sync_database_plugin.h | 297-------------------------------------------------------------------------------
Dsrc/include/sync_testing_lib.h | 135-------------------------------------------------------------------------------
Msrc/lib/sync_api_download.c | 2+-
Msrc/lib/sync_api_upload.c | 2+-
Msrc/sync/sync-httpd.c | 23+++++++----------------
Msrc/sync/sync-httpd.h | 7+------
Msrc/sync/sync-httpd2.c | 23+++++++----------------
Msrc/sync/sync-httpd2.h | 7+------
Msrc/sync/sync-httpd2_backup-post.c | 58+++++++++++++++++++++++++++++-----------------------------
Msrc/sync/sync-httpd2_backup.c | 20++++++++++----------
Msrc/sync/sync-httpd_backup.c | 20++++++++++----------
Msrc/sync/sync-httpd_backup_post.c | 58+++++++++++++++++++++++++++++-----------------------------
Msrc/syncdb/Makefile.am | 41+++++++++++++++++------------------------
Dsrc/syncdb/plugin_syncdb_postgres.c | 1364-------------------------------------------------------------------------------
Msrc/syncdb/sync-dbinit.c | 27++++++++++++---------------
Msrc/syncdb/sync_db_plugin.c | 4++--
Asrc/syncdb/syncdb_create_tables.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_drop_tables.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_gc.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_increment_lifetime_TR.c | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_lookup_account_TR.c | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_lookup_backup_TR.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_lookup_pending_payments_by_account_TR.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_pg.c | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_preflight.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_store_backup_TR.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_store_payment_TR.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/syncdb/syncdb_update_backup_TR.c | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/syncdb/test_sync_db.c | 193+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/testing/test_sync_api.c | 4++--
Msrc/testing/testing_api_cmd_backup_download.c | 4++--
Msrc/testing/testing_api_cmd_backup_upload.c | 6+++---
Msrc/testing/testing_api_traits.c | 2+-
Msrc/util/os_installation.c | 2+-
Msrc/util/sync-config.c | 2+-
57 files changed, 2403 insertions(+), 2139 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -317,6 +317,8 @@ doc/Makefile doc/doxygen/Makefile src/Makefile src/include/Makefile +src/include/sync/Makefile +src/include/sync/sync-database/Makefile src/lib/Makefile src/util/Makefile src/sync/Makefile diff --git a/debian/libsync-dev.install b/debian/libsync-dev.install @@ -1,2 +1,2 @@ -usr/include +usr/include/sync/* usr/lib/*/libsync* diff --git a/src/include/Makefile.am b/src/include/Makefile.am @@ -1,12 +1,5 @@ # This Makefile.am is in the public domain +SUBDIRS = . sync + EXTRA_DIST = \ platform.h - -talerincludedir = $(includedir)/taler - -talerinclude_HEADERS = \ - sync_database_lib.h \ - sync_database_plugin.h \ - sync_service.h \ - sync_testing_lib.h \ - sync_util.h diff --git a/src/include/sync/Makefile.am b/src/include/sync/Makefile.am @@ -0,0 +1,10 @@ +# This Makefile.am is in the public domain +SUBDIRS = . sync-database + +syncincludedir = $(includedir)/sync + +syncinclude_HEADERS = \ + sync_database_lib.h \ + sync_service.h \ + sync_testing_lib.h \ + sync_util.h diff --git a/src/include/sync/sync-database/Makefile.am b/src/include/sync/sync-database/Makefile.am @@ -0,0 +1,18 @@ +# This Makefile.am is in the public domain +SUBDIRS = . + +syncdbincludedir = $(includedir)/sync/sync-database + +syncdbinclude_HEADERS = \ + create_tables.h \ + common.h \ + drop_tables.h \ + gc.h \ + increment_lifetime_TR.h \ + lookup_account_TR.h \ + lookup_backup_TR.h \ + lookup_pending_payments_by_account_TR.h \ + preflight.h \ + store_backup_TR.h \ + store_payment_TR.h \ + update_backup_TR.h diff --git a/src/include/sync/sync-database/common.h b/src/include/sync/sync-database/common.h @@ -0,0 +1,72 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_common.h + * @brief common sync database definitions + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_COMMON_H +#define SYNC_DATABASE_COMMON_H + +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "sync/sync_service.h" +#include <jansson.h> +#include <taler/taler_util.h> + + +/** + * Possible status codes returned from the SYNC database. + */ +enum SYNC_DB_QueryStatus +{ + /** + * Client claimed to be updating an existing backup, but we have none. + */ + SYNC_DB_OLD_BACKUP_MISSING = -5, + + /** + * Update failed because the old backup hash does not match what we previously had in the DB. + */ + SYNC_DB_OLD_BACKUP_MISMATCH = -4, + + /** + * Account is unpaid / does not exist. + */ + SYNC_DB_PAYMENT_REQUIRED = -3, + + /** + * Hard database issue, retries futile. + */ + SYNC_DB_HARD_ERROR = -2, + + /** + * Soft database error, retrying may help. + */ + SYNC_DB_SOFT_ERROR = -1, + + /** + * Database succeeded, but no results. + */ + SYNC_DB_NO_RESULTS = 0, + + /** + * Database succeeded, one change or result. + */ + SYNC_DB_ONE_RESULT = 1 +}; + +#endif diff --git a/src/include/sync/sync-database/create_tables.h b/src/include/sync/sync-database/create_tables.h @@ -0,0 +1,34 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_create_tables.h + * @brief create sync database tables + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_CREATE_TABLES_H +#define SYNC_DATABASE_CREATE_TABLES_H + +#include <gnunet/gnunet_util_lib.h> + +/** + * Create the necessary tables if they are not present. + * + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +enum GNUNET_GenericReturnValue +SYNCDB_create_tables (void); + +#endif diff --git a/src/include/sync/sync-database/drop_tables.h b/src/include/sync/sync-database/drop_tables.h @@ -0,0 +1,34 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_drop_tables.h + * @brief drop sync tables + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_DROP_TABLES_H +#define SYNC_DATABASE_DROP_TABLES_H + +#include <gnunet/gnunet_util_lib.h> + +/** + * Drop sync tables. Used for testcases. + * + * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure + */ +enum GNUNET_GenericReturnValue +SYNCDB_drop_tables (void); + +#endif diff --git a/src/include/sync/sync-database/gc.h b/src/include/sync/sync-database/gc.h @@ -0,0 +1,43 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_gc.h + * @brief garbage collection for sync database + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_GC_H +#define SYNC_DATABASE_GC_H + +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> + +/** + * Function called to perform "garbage collection" on the + * database, expiring records we no longer require. Deletes + * all user records that are not paid up (and by cascade deletes + * the associated recovery documents). Also deletes expired + * truth and financial records older than @a fin_expire. + * + * @param expire_backups backups older than the given time stamp should be garbage collected + * @param expire_pending_payments payments still pending from since before + * this value should be garbage collected + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +SYNCDB_gc (struct GNUNET_TIME_Absolute expire, + struct GNUNET_TIME_Absolute expire_pending_payments); + +#endif diff --git a/src/include/sync/sync-database/increment_lifetime_TR.h b/src/include/sync/sync-database/increment_lifetime_TR.h @@ -0,0 +1,43 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_increment_lifetime_TR.h + * @brief increment account lifetime after payment + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_INCREMENT_LIFETIME_TR_H +#define SYNC_DATABASE_INCREMENT_LIFETIME_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include "sync/sync-database/common.h" + +/** + * Increment account lifetime and mark the associated payment + * as successful. + * + * @param account_pub which account received a payment + * @param order_id order which was paid, must be unique and match pending payment + * @param lifetime for how long is the account now paid (increment) + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_increment_lifetime_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const char *order_id, + struct GNUNET_TIME_Relative lifetime); + +#endif diff --git a/src/include/sync/sync-database/lookup_account_TR.h b/src/include/sync/sync-database/lookup_account_TR.h @@ -0,0 +1,40 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_lookup_account_TR.h + * @brief lookup account and backup metadata + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_LOOKUP_ACCOUNT_TR_H +#define SYNC_DATABASE_LOOKUP_ACCOUNT_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include "sync/sync-database/common.h" + +/** + * Lookup an account and associated backup meta data. + * + * @param account_pub account to look up + * @param[out] backup_hash set to hash of backup + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_lookup_account_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + struct GNUNET_HashCode *backup_hash); + +#endif diff --git a/src/include/sync/sync-database/lookup_backup_TR.h b/src/include/sync/sync-database/lookup_backup_TR.h @@ -0,0 +1,48 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_lookup_backup_TR.h + * @brief obtain backup data + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_LOOKUP_BACKUP_TR_H +#define SYNC_DATABASE_LOOKUP_BACKUP_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include "sync/sync-database/common.h" + +/** + * Obtain backup. + * + * @param account_pub account to obtain backup for + * @param[out] account_sig set to signature affirming storage request + * @param[out] prev_hash set to hash of the previous backup (all zeros if none) + * @param[out] backup_hash set to hash of backup + * @param[out] backup_size set to number of bytes in backup + * @param[out] backup set to raw data to backup, caller MUST FREE + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_lookup_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + struct SYNC_AccountSignatureP *account_sig, + struct GNUNET_HashCode *prev_hash, + struct GNUNET_HashCode *backup_hash, + size_t *backup_size, + void **backup); + +#endif diff --git a/src/include/sync/sync-database/lookup_pending_payments_by_account_TR.h b/src/include/sync/sync-database/lookup_pending_payments_by_account_TR.h @@ -0,0 +1,60 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_lookup_pending_payments_by_account_TR.h + * @brief lookup pending payments by account + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_LOOKUP_PENDING_PAYMENTS_BY_ACCOUNT_TR_H +#define SYNC_DATABASE_LOOKUP_PENDING_PAYMENTS_BY_ACCOUNT_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_db_lib.h> +#include "sync/sync_service.h" + + +/** + * Function called on all pending payments for an account. + * + * @param cls closure + * @param timestamp for how long have we been waiting + * @param order_id order id in the backend + * @param token claim token, or NULL for none + * @param amount how much is the order for + */ +typedef void +(*SYNC_DB_PaymentPendingIterator)(void *cls, + struct GNUNET_TIME_Timestamp timestamp, + const char *order_id, + const struct TALER_ClaimTokenP *token, + const struct TALER_Amount *amount); + + +/** + * Lookup pending payments by account. + * + * @param account_pub account to look for pending payments under + * @param it iterator to call on all pending payments + * @param it_cls closure for @a it + * @return transaction status + */ +enum GNUNET_DB_QueryStatus +SYNCDB_lookup_pending_payments_by_account_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + SYNC_DB_PaymentPendingIterator it, + void *it_cls); + +#endif diff --git a/src/include/sync/sync-database/preflight.h b/src/include/sync/sync-database/preflight.h @@ -0,0 +1,38 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_preflight.h + * @brief preflight check for sync database + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_PREFLIGHT_H +#define SYNC_DATABASE_PREFLIGHT_H + +#include <gnunet/gnunet_util_lib.h> + +/** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @return #GNUNET_OK if everything is fine + * #GNUNET_NO if a transaction was rolled back + * #GNUNET_SYSERR on hard errors + */ +enum GNUNET_GenericReturnValue +SYNCDB_preflight (void); + +#endif diff --git a/src/include/sync/sync-database/store_backup_TR.h b/src/include/sync/sync-database/store_backup_TR.h @@ -0,0 +1,48 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_store_backup_TR.h + * @brief store first backup + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_STORE_BACKUP_TR_H +#define SYNC_DATABASE_STORE_BACKUP_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include "sync/sync-database/common.h" + +/** + * Store backup. Only applicable for the FIRST backup under + * an @a account_pub. Use @e SYNCDB_update_backup_TR to update an + * existing backup. + * + * @param account_pub account to store @a backup under + * @param account_sig signature affirming storage request + * @param backup_hash hash of @a backup + * @param backup_size number of bytes in @a backup + * @param backup raw data to backup + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_store_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const struct SYNC_AccountSignatureP *account_sig, + const struct GNUNET_HashCode *backup_hash, + size_t backup_size, + const void *backup); + +#endif diff --git a/src/include/sync/sync-database/store_payment_TR.h b/src/include/sync/sync-database/store_payment_TR.h @@ -0,0 +1,47 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_store_payment_TR.h + * @brief store payment for sync database + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_STORE_PAYMENT_TR_H +#define SYNC_DATABASE_STORE_PAYMENT_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include <taler/taler_util.h> +#include "sync/sync-database/common.h" + +/** + * Store payment. Used to begin a payment, not indicative + * that the payment actually was made. (That is done + * when we increment the account's lifetime.) + * + * @param account_pub account to store @a backup under + * @param order_id order we created + * @param token claim token, or NULL for none + * @param amount how much we asked for + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_store_payment_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const char *order_id, + const struct TALER_ClaimTokenP *token, + const struct TALER_Amount *amount); + +#endif diff --git a/src/include/sync/sync-database/update_backup_TR.h b/src/include/sync/sync-database/update_backup_TR.h @@ -0,0 +1,48 @@ +/* + This file is part of GNU Taler + Copyright (C) 2019, 2021 Taler Systems SA + + Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + Taler 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 + Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_update_backup_TR.h + * @brief update existing backup + * @author Christian Grothoff + */ +#ifndef SYNC_DATABASE_UPDATE_BACKUP_TR_H +#define SYNC_DATABASE_UPDATE_BACKUP_TR_H + +#include <gnunet/gnunet_util_lib.h> +#include "sync/sync_service.h" +#include "sync/sync-database/common.h" + +/** + * Update backup. + * + * @param account_pub account to store @a backup under + * @param old_backup_hash hash of the previous backup (must match) + * @param account_sig signature affirming storage request + * @param backup_hash hash of @a backup + * @param backup_size number of bytes in @a backup + * @param backup raw data to backup + * @return transaction status + */ +enum SYNC_DB_QueryStatus +SYNCDB_update_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const struct GNUNET_HashCode *old_backup_hash, + const struct SYNC_AccountSignatureP *account_sig, + const struct GNUNET_HashCode *backup_hash, + size_t backup_size, + const void *backup); + +#endif diff --git a/src/include/sync/sync_database_lib.h b/src/include/sync/sync_database_lib.h @@ -0,0 +1,59 @@ +/* + This file is part of TALER + Copyright (C) 2014-2017 Inria & GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_database_lib.h + * @brief sync database library interface + */ +#ifndef SYNC_DB_LIB_H +#define SYNC_DB_LIB_H + +#include <taler/taler_util.h> +#include <sync/sync-database/drop_tables.h> +#include <sync/sync-database/create_tables.h> +#include <sync/sync-database/preflight.h> +#include <sync/sync-database/gc.h> +#include <sync/sync-database/store_payment_TR.h> +#include <sync/sync-database/lookup_pending_payments_by_account_TR.h> +#include <sync/sync-database/store_backup_TR.h> +#include <sync/sync-database/update_backup_TR.h> +#include <sync/sync-database/lookup_account_TR.h> +#include <sync/sync-database/lookup_backup_TR.h> +#include <sync/sync-database/increment_lifetime_TR.h> + +/** + * Initialize the sync database subsystem. + * + * @param cfg configuration to use + * @param skip_preflight true if we should skip the usual + * preflight check which assures us that the DB is actually + * operational; only sync-dbinit should use true here. + * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure + */ +enum GNUNET_GenericReturnValue +SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + bool skip_preflight); + + +/** + * Shutdown the sync database subsystem. + */ +void +SYNCDB_fini (void); + + +#endif /* SYNC_DB_LIB_H */ + +/* end of sync_database_lib.h */ diff --git a/src/include/sync_service.h b/src/include/sync/sync_service.h diff --git a/src/include/sync/sync_testing_lib.h b/src/include/sync/sync_testing_lib.h @@ -0,0 +1,135 @@ +/* + This file is part of TALER + (C) 2018, 2019 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER 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 TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file include/sync_testing_lib.h + * @brief API for writing an interpreter to test SYNC components + * @author Christian Grothoff <christian@grothoff.org> + */ +#ifndef SYNC_TESTING_LIB_H +#define SYNC_TESTING_LIB_H + +#include "sync/sync_service.h" +#include <gnunet/gnunet_json_lib.h> +#include <taler/taler_testing_lib.h> +#include <microhttpd.h> + + +/** + * Make the "backup download" command for a non-existent upload. + * + * @param label command label + * @param sync_url base URL of the sync serving + * the policy store request. + * @return the command + */ +struct TALER_TESTING_Command +SYNC_TESTING_cmd_backup_nx (const char *label, + const char *sync_url); + + +/** + * Make the "backup download" command. + * + * @param label command label + * @param sync_url base URL of the sync serving + * the policy store request. + * @param http_status expected HTTP status. + * @param upload_ref reference to upload command + * @return the command + */ +struct TALER_TESTING_Command +SYNC_TESTING_cmd_backup_download (const char *label, + const char *sync_url, + unsigned int http_status, + const char *upload_ref); + + +/** + * Types of options for performing the upload. Used as a bitmask. + */ +enum SYNC_TESTING_UploadOption +{ + /** + * Do everything by the book. + */ + SYNC_TESTING_UO_NONE = 0, + + /** + * Use random hash for previous upload instead of correct + * previous hash. + */ + SYNC_TESTING_UO_PREV_HASH_WRONG = 1, + + /** + * Request payment. + */ + SYNC_TESTING_UO_REQUEST_PAYMENT = 2, + + /** + * Reference payment order ID from linked previous upload. + */ + SYNC_TESTING_UO_REFERENCE_ORDER_ID = 4 + + +}; + + +/** + * Make the "backup upload" command. + * + * @param label command label + * @param sync_url base URL of the sync serving + * the policy store request. + * @param prev_upload reference to a previous upload we are + * supposed to update, NULL for none + * @param last_upload reference to the last upload for the + * same account, used to check result on MHD_HTTP_CONFLICT + * @param uo upload options + * @param http_status expected HTTP status. + * @param backup_data data to upload + * @param backup_data_size number of bytes in @a backup_data + * @return the command + */ +struct TALER_TESTING_Command +SYNC_TESTING_cmd_backup_upload (const char *label, + const char *sync_url, + const char *prev_upload, + const char *last_upload, + enum SYNC_TESTING_UploadOption uo, + unsigned int http_status, + const void *backup_data, + size_t backup_data_size); + +/** + * Call @a op on all simple traits. + * + * @param op macro to call + */ +#define SYNC_TESTING_SIMPLE_TRAITS(op) \ + op (sync_account_pub, const struct SYNC_AccountPublicKeyP) \ + op (sync_account_priv, const struct SYNC_AccountPrivateKeyP) \ + op (prev_hash, const struct GNUNET_HashCode) \ + op (curr_hash, const struct GNUNET_HashCode) + + +/* FIXME: eventually switch to libgnunettesting with the SYNC_ prefix for + the symbols instead of TALER_TESTING_! */ +SYNC_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_DECL_SIMPLE_TRAIT) + +#endif diff --git a/src/include/sync_util.h b/src/include/sync/sync_util.h diff --git a/src/include/sync_database_lib.h b/src/include/sync_database_lib.h @@ -1,50 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2017 Inria & GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER 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 - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * - */ -#ifndef SYNC_DB_LIB_H -#define SYNC_DB_LIB_H - -#include <taler/taler_util.h> -#include "sync_database_plugin.h" - -/** - * Initialize the plugin. - * - * @param cfg configuration to use - * @param skip_preflight true if we should skip the usual - * preflight check which assures us that the DB is actually - * operational; only sync-dbinit should use true here. - * @return NULL on failure - */ -struct SYNC_DatabasePlugin * -SYNC_DB_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg, - bool skip_preflight); - - -/** - * Shutdown the plugin. - * - * @param[in] plugin plugin to unload - */ -void -SYNC_DB_plugin_unload (struct SYNC_DatabasePlugin *plugin); - - -#endif /* SYNC_DB_LIB_H */ - -/* end of sync_database_lib.h */ diff --git a/src/include/sync_database_plugin.h b/src/include/sync_database_plugin.h @@ -1,297 +0,0 @@ -/* - This file is part of GNU Taler - Copyright (C) 2019, 2021 Taler Systems SA - - Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - Taler 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 - Taler; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file include/sync_database_plugin.h - * @brief database access for Sync - * @author Christian Grothoff - */ -#ifndef SYNC_DATABASE_PLUGIN_H -#define SYNC_DATABASE_PLUGIN_H - -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_db_lib.h> -#include "sync_service.h" -#include <jansson.h> -#include <taler/taler_util.h> - - -/** - * Possible status codes returned from the SYNC database. - */ -enum SYNC_DB_QueryStatus -{ - /** - * Client claimed to be updating an existing backup, but we have none. - */ - SYNC_DB_OLD_BACKUP_MISSING = -5, - - /** - * Update failed because the old backup hash does not match what we previously had in the DB. - */ - SYNC_DB_OLD_BACKUP_MISMATCH = -4, - - /** - * Account is unpaid / does not exist. - */ - SYNC_DB_PAYMENT_REQUIRED = -3, - - /** - * Hard database issue, retries futile. - */ - SYNC_DB_HARD_ERROR = -2, - - /** - * Soft database error, retrying may help. - */ - SYNC_DB_SOFT_ERROR = -1, - - /** - * Database succeeded, but no results. - */ - SYNC_DB_NO_RESULTS = 0, - - /** - * Database succeeded, one change or result. - */ - SYNC_DB_ONE_RESULT = 1 -}; - - -/** - * Function called on all pending payments for an account. - * - * @param cls closure - * @param timestamp for how long have we been waiting - * @param order_id order id in the backend - * @param token claim token, or NULL for none - * @param amount how much is the order for - */ -typedef void -(*SYNC_DB_PaymentPendingIterator)(void *cls, - struct GNUNET_TIME_Timestamp timestamp, - const char *order_id, - const struct TALER_ClaimTokenP *token, - const struct TALER_Amount *amount); - - -/** - * Handle to interact with the database. - * - * Functions ending with "_TR" run their OWN transaction scope - * and MUST NOT be called from within a transaction setup by the - * caller. Functions ending with "_NT" require the caller to - * setup a transaction scope. Functions without a suffix are - * simple, single SQL queries that MAY be used either way. - */ -struct SYNC_DatabasePlugin -{ - - /** - * Closure for all callbacks. - */ - void *cls; - - /** - * Name of the library which generated this plugin. Set by the - * plugin loader. - */ - char *library_name; - - /** - * Drop sync tables. Used for testcases. - * - * @param cls closure - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ - enum GNUNET_GenericReturnValue - (*drop_tables)(void *cls); - - - /** - * Create the necessary tables if they are not present - * - * @param cls the @e cls of this struct with the plugin-specific state - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ - enum GNUNET_GenericReturnValue - (*create_tables)(void *cls); - - - /** - * Do a pre-flight check that we are not in an uncommitted transaction. - * If we are, try to commit the previous transaction and output a warning. - * Does not return anything, as we will continue regardless of the outcome. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @return #GNUNET_OK if everything is fine - * #GNUNET_NO if a transaction was rolled back - * #GNUNET_SYSERR on hard errors - */ - enum GNUNET_GenericReturnValue - (*preflight)(void *cls); - - - /** - * Function called to perform "garbage collection" on the - * database, expiring records we no longer require. Deletes - * all user records that are not paid up (and by cascade deletes - * the associated recovery documents). Also deletes expired - * truth and financial records older than @a fin_expire. - * - * @param cls closure - * @param expire_backups backups older than the given time stamp should be garbage collected - * @param expire_pending_payments payments still pending from since before - * this value should be garbage collected - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*gc)(void *cls, - struct GNUNET_TIME_Absolute expire, - struct GNUNET_TIME_Absolute expire_pending_payments); - - - /** - * Store backup. Only applicable for the FIRST backup under - * an @a account_pub. Use @e update_backup_TR to update an - * existing backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param account_sig signature affirming storage request - * @param backup_hash hash of @a backup - * @param backup_size number of bytes in @a backup - * @param backup raw data to backup - * @return transaction status - */ - enum SYNC_DB_QueryStatus - (*store_backup_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const struct SYNC_AccountSignatureP *account_sig, - const struct GNUNET_HashCode *backup_hash, - size_t backup_size, - const void *backup); - - - /** - * Store payment. Used to begin a payment, not indicative - * that the payment actually was made. (That is done - * when we increment the account's lifetime.) - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param order_id order we created - * @param token claim token, or NULL for none - * @param amount how much we asked for - * @return transaction status - */ - enum SYNC_DB_QueryStatus - (*store_payment_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const char *order_id, - const struct TALER_ClaimTokenP *token, - const struct TALER_Amount *amount); - - - /** - * Lookup pending payments by account. - * - * @param cls closure - * @param account_pub account to look for pending payments under - * @param it iterator to call on all pending payments - * @param it_cls closure for @a it - * @return transaction status - */ - enum GNUNET_DB_QueryStatus - (*lookup_pending_payments_by_account_TR)(void *cls, - const struct - SYNC_AccountPublicKeyP *account_pub, - SYNC_DB_PaymentPendingIterator it, - void *it_cls); - - /** - * Update backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param account_sig signature affirming storage request - * @param old_backup_hash hash of the previous backup (must match) - * @param backup_hash hash of @a backup - * @param backup_size number of bytes in @a backup - * @param backup raw data to backup - * @return transaction status - */ - enum SYNC_DB_QueryStatus - (*update_backup_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const struct GNUNET_HashCode *old_backup_hash, - const struct SYNC_AccountSignatureP *account_sig, - const struct GNUNET_HashCode *backup_hash, - size_t backup_size, - const void *backup); - - - /** - * Lookup an account and associated backup meta data. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param backup_hash[OUT] set to hash of @a backup - * @return transaction status - */ - enum SYNC_DB_QueryStatus - (*lookup_account_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - struct GNUNET_HashCode *backup_hash); - - - /** - * Obtain backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param account_sig[OUT] set to signature affirming storage request - * @param prev_hash[OUT] set to hash of the previous @a backup (all zeros if none) - * @param backup_hash[OUT] set to hash of @a backup - * @param backup_size[OUT] set to number of bytes in @a backup - * @param backup[OUT] set to raw data to backup, caller MUST FREE - */ - enum SYNC_DB_QueryStatus - (*lookup_backup_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - struct SYNC_AccountSignatureP *account_sig, - struct GNUNET_HashCode *prev_hash, - struct GNUNET_HashCode *backup_hash, - size_t *backup_size, - void **backup); - - /** - * Increment account lifetime and mark the associated payment - * as successful. - * - * @param cls closure - * @param account_pub which account received a payment - * @param order_id order which was paid, must be unique and match pending payment - * @param lifetime for how long is the account now paid (increment) - * @return transaction status - */ - enum SYNC_DB_QueryStatus - (*increment_lifetime_TR)(void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const char *order_id, - struct GNUNET_TIME_Relative lifetime); - -}; -#endif diff --git a/src/include/sync_testing_lib.h b/src/include/sync_testing_lib.h @@ -1,135 +0,0 @@ -/* - This file is part of TALER - (C) 2018, 2019 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER 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 TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file include/sync_testing_lib.h - * @brief API for writing an interpreter to test SYNC components - * @author Christian Grothoff <christian@grothoff.org> - */ -#ifndef SYNC_TESTING_LIB_H -#define SYNC_TESTING_LIB_H - -#include "sync_service.h" -#include <gnunet/gnunet_json_lib.h> -#include <taler/taler_testing_lib.h> -#include <microhttpd.h> - - -/** - * Make the "backup download" command for a non-existent upload. - * - * @param label command label - * @param sync_url base URL of the sync serving - * the policy store request. - * @return the command - */ -struct TALER_TESTING_Command -SYNC_TESTING_cmd_backup_nx (const char *label, - const char *sync_url); - - -/** - * Make the "backup download" command. - * - * @param label command label - * @param sync_url base URL of the sync serving - * the policy store request. - * @param http_status expected HTTP status. - * @param upload_ref reference to upload command - * @return the command - */ -struct TALER_TESTING_Command -SYNC_TESTING_cmd_backup_download (const char *label, - const char *sync_url, - unsigned int http_status, - const char *upload_ref); - - -/** - * Types of options for performing the upload. Used as a bitmask. - */ -enum SYNC_TESTING_UploadOption -{ - /** - * Do everything by the book. - */ - SYNC_TESTING_UO_NONE = 0, - - /** - * Use random hash for previous upload instead of correct - * previous hash. - */ - SYNC_TESTING_UO_PREV_HASH_WRONG = 1, - - /** - * Request payment. - */ - SYNC_TESTING_UO_REQUEST_PAYMENT = 2, - - /** - * Reference payment order ID from linked previous upload. - */ - SYNC_TESTING_UO_REFERENCE_ORDER_ID = 4 - - -}; - - -/** - * Make the "backup upload" command. - * - * @param label command label - * @param sync_url base URL of the sync serving - * the policy store request. - * @param prev_upload reference to a previous upload we are - * supposed to update, NULL for none - * @param last_upload reference to the last upload for the - * same account, used to check result on MHD_HTTP_CONFLICT - * @param uo upload options - * @param http_status expected HTTP status. - * @param backup_data data to upload - * @param backup_data_size number of bytes in @a backup_data - * @return the command - */ -struct TALER_TESTING_Command -SYNC_TESTING_cmd_backup_upload (const char *label, - const char *sync_url, - const char *prev_upload, - const char *last_upload, - enum SYNC_TESTING_UploadOption uo, - unsigned int http_status, - const void *backup_data, - size_t backup_data_size); - -/** - * Call @a op on all simple traits. - * - * @param op macro to call - */ -#define SYNC_TESTING_SIMPLE_TRAITS(op) \ - op (sync_account_pub, const struct SYNC_AccountPublicKeyP) \ - op (sync_account_priv, const struct SYNC_AccountPrivateKeyP) \ - op (prev_hash, const struct GNUNET_HashCode) \ - op (curr_hash, const struct GNUNET_HashCode) - - -/* FIXME: eventually switch to libgnunettesting with the SYNC_ prefix for - the symbols instead of TALER_TESTING_! */ -SYNC_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_DECL_SIMPLE_TRAIT) - -#endif diff --git a/src/lib/sync_api_download.c b/src/lib/sync_api_download.c @@ -29,7 +29,7 @@ #include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_curl_lib.h> #include <taler/taler_signatures.h> -#include "sync_service.h" +#include "sync/sync_service.h" #include "sync_api_curl_defaults.h" diff --git a/src/lib/sync_api_upload.c b/src/lib/sync_api_upload.c @@ -30,7 +30,7 @@ #include <gnunet/gnunet_curl_lib.h> #include <taler/taler_signatures.h> #include <taler/taler_json_lib.h> -#include "sync_service.h" +#include "sync/sync_service.h" #include "sync_api_curl_defaults.h" diff --git a/src/sync/sync-httpd.c b/src/sync/sync-httpd.c @@ -21,10 +21,10 @@ #include "platform.h" #include <microhttpd.h> #include <gnunet/gnunet_util_lib.h> -#include "sync_util.h" +#include "sync/sync_util.h" #include "sync-httpd.h" #include "sync-httpd_mhd.h" -#include "sync_database_lib.h" +#include "sync/sync_database_lib.h" #include "sync-httpd_backup.h" #include "sync-httpd_config.h" @@ -75,11 +75,6 @@ static int global_ret; static bool have_daemons; /** - * Connection handle to the our database - */ -struct SYNC_DatabasePlugin *db; - -/** * Username and password to use for client authentication * (optional). */ @@ -337,11 +332,7 @@ do_shutdown (void *cls) rc = NULL; } TALER_MHD_daemons_destroy (); - if (NULL != db) - { - SYNC_DB_plugin_unload (db); - db = NULL; - } + SYNCDB_fini (); } @@ -563,16 +554,16 @@ run (void *cls, GNUNET_free (auth_header); } - if (NULL == - (db = SYNC_DB_plugin_load (config, - false))) + if (GNUNET_OK != + SYNCDB_init (config, + false)) { global_ret = EXIT_NOTCONFIGURED; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != - db->preflight (db->cls)) + SYNCDB_preflight ()) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database not setup. Did you run sync-dbinit?\n"); diff --git a/src/sync/sync-httpd.h b/src/sync/sync-httpd.h @@ -24,7 +24,7 @@ #include "platform.h" #include <microhttpd.h> #include <taler/taler_mhd_lib.h> -#include "sync_database_lib.h" +#include "sync/sync_database_lib.h" #include <gnunet/gnunet_mhd_compat.h> /** @@ -124,11 +124,6 @@ struct TM_HandlerContext /** - * Handle to the database backend. - */ -extern struct SYNC_DatabasePlugin *db; - -/** * Upload limit to the service, in megabytes. */ extern unsigned long long SH_upload_limit_mb; diff --git a/src/sync/sync-httpd2.c b/src/sync/sync-httpd2.c @@ -20,9 +20,9 @@ */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> -#include "sync_util.h" +#include "sync/sync_util.h" #include "sync-httpd2.h" -#include "sync_database_lib.h" +#include "sync/sync_database_lib.h" #include "sync-httpd2_backup.h" #include "sync-httpd2_config.h" @@ -73,11 +73,6 @@ static int global_ret; static bool have_daemons; /** - * Connection handle to the our database - */ -struct SYNC_DatabasePlugin *db; - -/** * Username and password to use for client authentication * (optional). */ @@ -321,11 +316,7 @@ do_shutdown (void *cls) rc = NULL; } TALER_MHD2_daemons_destroy (); - if (NULL != db) - { - SYNC_DB_plugin_unload (db); - db = NULL; - } + SYNCDB_fini (); } @@ -511,16 +502,16 @@ run (void *cls, GNUNET_free (auth_header); } - if (NULL == - (db = SYNC_DB_plugin_load (config, - false))) + if (GNUNET_OK != + SYNCDB_init (config, + false)) { global_ret = EXIT_NOTCONFIGURED; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != - db->preflight (db->cls)) + SYNCDB_preflight ()) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database not setup. Did you run sync-dbinit?\n"); diff --git a/src/sync/sync-httpd2.h b/src/sync/sync-httpd2.h @@ -24,7 +24,7 @@ #include "platform.h" #include <microhttpd2.h> #include <taler/taler_mhd2_lib.h> -#include "sync_database_lib.h" +#include "sync/sync_database_lib.h" /** * @brief Struct describing an URL and the handler for it. @@ -97,11 +97,6 @@ struct TM_HandlerContext /** - * Handle to the database backend. - */ -extern struct SYNC_DatabasePlugin *db; - -/** * Upload limit to the service, in megabytes. */ extern unsigned long long SH_upload_limit_mb; diff --git a/src/sync/sync-httpd2_backup-post.c b/src/sync/sync-httpd2_backup-post.c @@ -311,11 +311,11 @@ proposal_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Storing payment request for order `%s'\n", por->details.ok.order_id); - qs = db->store_payment_TR (db->cls, - &bc->account, - por->details.ok.order_id, - por->details.ok.token, - &SH_annual_fee); + qs = SYNCDB_store_payment_TR ( + &bc->account, + por->details.ok.order_id, + por->details.ok.token, + &SH_annual_fee); if (0 >= qs) { GNUNET_break (0); @@ -429,10 +429,10 @@ check_payment_cb (void *cls, { enum SYNC_DB_QueryStatus qs; - qs = db->increment_lifetime_TR (db->cls, - &bc->account, - bc->order_id, - GNUNET_TIME_UNIT_YEARS); /* always annual */ + qs = SYNCDB_increment_lifetime_TR ( + &bc->account, + bc->order_id, + GNUNET_TIME_UNIT_YEARS); /* always annual */ if (0 <= qs) return; /* continue as planned */ GNUNET_break (0); @@ -519,10 +519,10 @@ begin_payment (struct BackupContext *bc, { enum GNUNET_DB_QueryStatus qs; - qs = db->lookup_pending_payments_by_account_TR (db->cls, - &bc->account, - &ongoing_payment_cb, - bc); + qs = SYNCDB_lookup_pending_payments_by_account_TR ( + &bc->account, + &ongoing_payment_cb, + bc); if (qs < 0) { GNUNET_break (0); @@ -712,24 +712,24 @@ handle_upload (void *upload_cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Uploading first backup to account\n"); - qs = db->store_backup_TR (db->cls, - &bc->account, - &bc->account_sig, - &bc->new_backup_hash, - content_data_size, - content_data); + qs = SYNCDB_store_backup_TR ( + &bc->account, + &bc->account_sig, + &bc->new_backup_hash, + content_data_size, + content_data); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Uploading existing backup of account\n"); - qs = db->update_backup_TR (db->cls, - &bc->account, - &bc->old_backup_hash, - &bc->account_sig, - &bc->new_backup_hash, - content_data_size, - content_data); + qs = SYNCDB_update_backup_TR ( + &bc->account, + &bc->old_backup_hash, + &bc->account_sig, + &bc->new_backup_hash, + content_data_size, + content_data); } if (qs < 0) { @@ -924,9 +924,9 @@ SH_backup_post (struct MHD_Request *request, struct GNUNET_HashCode hc; enum SYNC_DB_QueryStatus qs; - qs = db->lookup_account_TR (db->cls, - account, - &hc); + qs = SYNCDB_lookup_account_TR ( + account, + &hc); if (qs < 0) { bool suspend; diff --git a/src/sync/sync-httpd2_backup.c b/src/sync/sync-httpd2_backup.c @@ -39,9 +39,9 @@ SH_backup_get (struct MHD_Request *request, struct GNUNET_HashCode backup_hash; enum SYNC_DB_QueryStatus qs; - qs = db->lookup_account_TR (db->cls, - account, - &backup_hash); + qs = SYNCDB_lookup_account_TR ( + account, + &backup_hash); switch (qs) { case SYNC_DB_OLD_BACKUP_MISSING: @@ -152,13 +152,13 @@ SH_make_backup (const struct SYNC_AccountPublicKeyP *account, size_t backup_size; void *backup; - qs = db->lookup_backup_TR (db->cls, - account, - &account_sig, - &prev_hash, - &backup_hash, - &backup_size, - &backup); + qs = SYNCDB_lookup_backup_TR ( + account, + &account_sig, + &prev_hash, + &backup_hash, + &backup_size, + &backup); switch (qs) { case SYNC_DB_OLD_BACKUP_MISSING: diff --git a/src/sync/sync-httpd_backup.c b/src/sync/sync-httpd_backup.c @@ -40,9 +40,9 @@ SH_backup_get (struct MHD_Connection *connection, enum SYNC_DB_QueryStatus qs; MHD_RESULT ret; - qs = db->lookup_account_TR (db->cls, - account, - &backup_hash); + qs = SYNCDB_lookup_account_TR ( + account, + &backup_hash); switch (qs) { case SYNC_DB_OLD_BACKUP_MISSING: @@ -165,13 +165,13 @@ SH_return_backup (struct MHD_Connection *connection, size_t backup_size; void *backup; - qs = db->lookup_backup_TR (db->cls, - account, - &account_sig, - &prev_hash, - &backup_hash, - &backup_size, - &backup); + qs = SYNCDB_lookup_backup_TR ( + account, + &account_sig, + &prev_hash, + &backup_hash, + &backup_size, + &backup); switch (qs) { case SYNC_DB_OLD_BACKUP_MISSING: diff --git a/src/sync/sync-httpd_backup_post.c b/src/sync/sync-httpd_backup_post.c @@ -335,11 +335,11 @@ proposal_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Storing payment request for order `%s'\n", por->details.ok.order_id); - qs = db->store_payment_TR (db->cls, - &bc->account, - por->details.ok.order_id, - por->details.ok.token, - &SH_annual_fee); + qs = SYNCDB_store_payment_TR ( + &bc->account, + por->details.ok.order_id, + por->details.ok.token, + &SH_annual_fee); if (0 >= qs) { GNUNET_break (0); @@ -456,10 +456,10 @@ check_payment_cb (void *cls, { enum SYNC_DB_QueryStatus qs; - qs = db->increment_lifetime_TR (db->cls, - &bc->account, - bc->order_id, - GNUNET_TIME_UNIT_YEARS); /* always annual */ + qs = SYNCDB_increment_lifetime_TR ( + &bc->account, + bc->order_id, + GNUNET_TIME_UNIT_YEARS); /* always annual */ if (0 <= qs) return; /* continue as planned */ GNUNET_break (0); @@ -547,10 +547,10 @@ begin_payment (struct BackupContext *bc, { enum GNUNET_DB_QueryStatus qs; - qs = db->lookup_pending_payments_by_account_TR (db->cls, - &bc->account, - &ongoing_payment_cb, - bc); + qs = SYNCDB_lookup_pending_payments_by_account_TR ( + &bc->account, + &ongoing_payment_cb, + bc); if (qs < 0) { struct MHD_Response *resp; @@ -852,9 +852,9 @@ SH_backup_post (struct MHD_Connection *connection, struct GNUNET_HashCode hc; enum SYNC_DB_QueryStatus qs; - qs = db->lookup_account_TR (db->cls, - account, - &hc); + qs = SYNCDB_lookup_account_TR ( + account, + &hc); if (qs < 0) return handle_database_error (bc, qs); @@ -976,24 +976,24 @@ SH_backup_post (struct MHD_Connection *connection, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Uploading first backup to account\n"); - qs = db->store_backup_TR (db->cls, - account, - &bc->account_sig, - &bc->new_backup_hash, - bc->upload_size, - bc->upload); + qs = SYNCDB_store_backup_TR ( + account, + &bc->account_sig, + &bc->new_backup_hash, + bc->upload_size, + bc->upload); } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Uploading existing backup of account\n"); - qs = db->update_backup_TR (db->cls, - account, - &bc->old_backup_hash, - &bc->account_sig, - &bc->new_backup_hash, - bc->upload_size, - bc->upload); + qs = SYNCDB_update_backup_TR ( + account, + &bc->old_backup_hash, + &bc->account_sig, + &bc->new_backup_hash, + bc->upload_size, + bc->upload); } if (qs < 0) return handle_database_error (bc, diff --git a/src/syncdb/Makefile.am b/src/syncdb/Makefile.am @@ -6,15 +6,6 @@ pkgcfgdir = $(prefix)/share/sync/config.d/ pkgcfg_DATA = \ sync_db_postgres.conf -plugindir = $(libdir)/sync - -if HAVE_POSTGRESQL -if HAVE_GNUNETPQ -plugin_LTLIBRARIES = \ - libsync_plugin_db_postgres.la -endif -endif - if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov @@ -36,38 +27,40 @@ sync_dbinit_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libsyncutil.la \ libsyncdb.la \ + -ltalerpq \ -ltalerutil \ + -lgnunetpq \ -lgnunetutil \ + -lpq \ $(XLIB) lib_LTLIBRARIES = \ libsyncdb.la libsyncdb_la_SOURCES = \ - sync_db_plugin.c + syncdb_pg.c syncdb_pg.h \ + syncdb_drop_tables.c \ + syncdb_create_tables.c \ + syncdb_preflight.c \ + syncdb_gc.c \ + syncdb_store_payment_TR.c \ + syncdb_lookup_pending_payments_by_account_TR.c \ + syncdb_store_backup_TR.c \ + syncdb_update_backup_TR.c \ + syncdb_lookup_account_TR.c \ + syncdb_lookup_backup_TR.c \ + syncdb_increment_lifetime_TR.c libsyncdb_la_LIBADD = \ $(top_builddir)/src/util/libsyncutil.la \ + -ltalerpq \ -lgnunetpq \ -lpq \ -lgnunetutil \ - -lltdl \ $(XLIB) libsyncdb_la_LDFLAGS = \ $(POSTGRESQL_LDFLAGS) \ - -version-info 0:1:0 \ + -version-info 1:0:0 \ -no-undefined -libsync_plugin_db_postgres_la_SOURCES = \ - plugin_syncdb_postgres.c -libsync_plugin_db_postgres_la_LDFLAGS = \ - $(SYNC_PLUGIN_LDFLAGS) -libsync_plugin_db_postgres_la_LIBADD = \ - $(LTLIBINTL) \ - -ltalerpq \ - -lgnunetpq \ - -lgnunetutil \ - -lpq \ - $(XLIB) - check_PROGRAMS = \ $(TESTS) diff --git a/src/syncdb/plugin_syncdb_postgres.c b/src/syncdb/plugin_syncdb_postgres.c @@ -1,1364 +0,0 @@ -/* - This file is part of TALER - (C) 2014--2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of ANASTASISABILITY 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 - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file syncdb/plugin_syncdb_postgres.c - * @brief database helper functions for postgres used by sync - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_db_lib.h> -#include <gnunet/gnunet_pq_lib.h> -#include <taler/taler_pq_lib.h> -#include "sync_database_plugin.h" -#include "sync_database_lib.h" - -/** - * Type of the "cls" argument given to each of the functions in - * our API. - */ -struct PostgresClosure -{ - - /** - * Postgres connection handle. - */ - struct GNUNET_PQ_Context *conn; - - /** - * Directory with SQL statements to run to create tables. - */ - char *sql_dir; - - /** - * Underlying configuration. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Name of the currently active transaction, NULL if none is active. - */ - const char *transaction_name; - - /** - * Currency we accept payments in. - */ - char *currency; - - /** - * Did we initialize the prepared statements - * for this session? - */ - bool init; - -}; - - -/** - * Drop sync tables - * - * @param cls closure our `struct Plugin` - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static enum GNUNET_GenericReturnValue -postgres_drop_tables (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_Context *conn; - enum GNUNET_GenericReturnValue ret; - - if (NULL != pg->conn) - { - GNUNET_PQ_disconnect (pg->conn); - pg->conn = NULL; - pg->init = false; - } - conn = GNUNET_PQ_connect_with_cfg (pg->cfg, - "syncdb-postgres", - NULL, - NULL, - NULL); - if (NULL == conn) - return GNUNET_SYSERR; - ret = GNUNET_PQ_exec_sql (conn, - "drop"); - GNUNET_PQ_disconnect (conn); - return ret; -} - - -/** - * Establish connection to the database. - * - * @param cls plugin context - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static enum GNUNET_GenericReturnValue -prepare_statements (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_PreparedStatement ps[] = { - GNUNET_PQ_make_prepare ("account_insert", - "INSERT INTO accounts " - "(account_pub" - ",expiration_date" - ") VALUES " - "($1,$2);"), - GNUNET_PQ_make_prepare ("payment_insert", - "INSERT INTO payments " - "(account_pub" - ",order_id" - ",token" - ",timestamp" - ",amount" - ") VALUES " - "($1,$2,$3,$4,$5);"), - GNUNET_PQ_make_prepare ("payment_done", - "UPDATE payments " - "SET" - " paid=TRUE " - "WHERE" - " order_id=$1" - " AND" - " account_pub=$2" - " AND" - " paid=FALSE;"), - GNUNET_PQ_make_prepare ("account_update", - "UPDATE accounts " - "SET" - " expiration_date=$1 " - "WHERE" - " account_pub=$2;"), - GNUNET_PQ_make_prepare ("account_select", - "SELECT" - " expiration_date " - "FROM" - " accounts " - "WHERE" - " account_pub=$1;"), - GNUNET_PQ_make_prepare ("payments_select", - "SELECT" - " account_pub" - ",order_id" - ",amount" - " FROM payments" - " WHERE paid=FALSE;"), - GNUNET_PQ_make_prepare ("payments_select_by_account", - "SELECT" - " timestamp" - ",order_id" - ",token" - ",amount" - " FROM payments" - " WHERE" - " paid=FALSE" - " AND" - " account_pub=$1;"), - GNUNET_PQ_make_prepare ("gc_accounts", - "DELETE FROM accounts " - "WHERE" - " expiration_date < $1;"), - GNUNET_PQ_make_prepare ("gc_pending_payments", - "DELETE FROM payments " - "WHERE" - " paid=FALSE" - " AND" - " timestamp < $1;"), - GNUNET_PQ_make_prepare ("backup_insert", - "INSERT INTO backups " - "(account_pub" - ",account_sig" - ",prev_hash" - ",backup_hash" - ",data" - ") VALUES " - "($1,$2,$3,$4,$5);"), - GNUNET_PQ_make_prepare ("backup_update", - "UPDATE backups " - " SET" - " backup_hash=$1" - ",account_sig=$2" - ",prev_hash=$3" - ",data=$4" - " WHERE" - " account_pub=$5" - " AND" - " backup_hash=$6;"), - GNUNET_PQ_make_prepare ("backup_select_hash", - "SELECT " - " backup_hash " - "FROM" - " backups " - "WHERE" - " account_pub=$1;"), - GNUNET_PQ_make_prepare ("backup_select", - "SELECT " - " account_sig" - ",prev_hash" - ",backup_hash" - ",data " - "FROM" - " backups " - "WHERE" - " account_pub=$1;"), - GNUNET_PQ_make_prepare ("do_commit", - "COMMIT"), - GNUNET_PQ_PREPARED_STATEMENT_END - }; - enum GNUNET_GenericReturnValue ret; - - ret = GNUNET_PQ_prepare_statements (pg->conn, - ps); - if (GNUNET_OK != ret) - return ret; - pg->init = true; - return GNUNET_OK; -} - - -/** - * Connect to the database if the connection does not exist yet. - * - * @param pg the plugin-specific state - * @param skip_prepare true if we should skip prepared statement setup - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -internal_setup (struct PostgresClosure *pg) -{ - if (NULL == pg->conn) - { -#if AUTO_EXPLAIN - /* Enable verbose logging to see where queries do not - properly use indices */ - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), - GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), - /* https://wiki.postgresql.org/wiki/Serializable suggests to really - force the default to 'serializable' if SSI is to be used. */ - GNUNET_PQ_make_try_execute ( - "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), - GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), - GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), - GNUNET_PQ_make_execute ("SET search_path TO sync;"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; -#else - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("SET search_path TO sync;"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; -#endif - struct GNUNET_PQ_Context *db_conn; - - db_conn = GNUNET_PQ_connect_with_cfg2 (pg->cfg, - "syncdb-postgres", - "sync-", - es, - NULL, - GNUNET_PQ_FLAG_CHECK_CURRENT); - if (NULL == db_conn) - return GNUNET_SYSERR; - pg->conn = db_conn; - } - if (NULL == pg->transaction_name) - GNUNET_PQ_reconnect_if_down (pg->conn); - if (pg->init) - return GNUNET_OK; - return prepare_statements (pg); -} - - -/** - * Do a pre-flight check that we are not in an uncommitted transaction. - * If we are, try to commit the previous transaction and output a warning. - * Does not return anything, as we will continue regardless of the outcome. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @return #GNUNET_OK if everything is fine - * #GNUNET_NO if a transaction was rolled back - * #GNUNET_SYSERR on hard errors - */ -static enum GNUNET_GenericReturnValue -postgres_preflight (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("ROLLBACK"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - if (! pg->init) - { - if (GNUNET_OK != - internal_setup (pg)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to ensure DB is initialized\n"); - return GNUNET_SYSERR; - } - } - if (NULL == pg->transaction_name) - return GNUNET_OK; /* all good */ - if (GNUNET_OK == - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "BUG: Preflight check rolled back transaction `%s'!\n", - pg->transaction_name); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "BUG: Preflight check failed to rollback transaction `%s'!\n", - pg->transaction_name); - } - pg->transaction_name = NULL; - return GNUNET_NO; -} - - -/** - * Check that the database connection is still up. - * - * @param cls a `struct PostgresClosure` with connection to check - */ -static void -check_connection (void *cls) -{ - struct PostgresClosure *pg = cls; - - GNUNET_PQ_reconnect_if_down (pg->conn); -} - - -/** - * Start a transaction. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param name unique name identifying the transaction (for debugging), - * must point to a constant - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -begin_transaction (void *cls, - const char *name) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - check_connection (pg); - postgres_preflight (pg); - pg->transaction_name = name; - if (GNUNET_OK != - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - TALER_LOG_ERROR ("Failed to start transaction\n"); - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Roll back the current transaction of a database connection. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - */ -static void -rollback (void *cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("ROLLBACK"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (pg->conn, - es)) - { - TALER_LOG_ERROR ("Failed to rollback transaction\n"); - GNUNET_break (0); - } - pg->transaction_name = NULL; -} - - -/** - * Commit the current transaction of a database connection. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @return transaction status code - */ -static enum GNUNET_DB_QueryStatus -commit_transaction (void *cls) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_PQ_QueryParam no_params[] = { - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "do_commit", - no_params); - pg->transaction_name = NULL; - return qs; -} - - -/** - * Function called to perform "garbage collection" on the - * database, expiring records we no longer require. Deletes - * all user records that are not paid up (and by cascade deletes - * the associated recovery documents). Also deletes expired - * truth and financial records older than @a fin_expire. - * - * @param cls closure - * @param expire_backups backups older than the given time stamp should be garbage collected - * @param expire_pending_payments payments still pending from since before - * this value should be garbage collected - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_gc (void *cls, - struct GNUNET_TIME_Absolute expire_backups, - struct GNUNET_TIME_Absolute expire_pending_payments) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&expire_backups), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_QueryParam params2[] = { - GNUNET_PQ_query_param_absolute_time (&expire_pending_payments), - GNUNET_PQ_query_param_end - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - postgres_preflight (pg); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "gc_accounts", - params); - if (qs < 0) - return qs; - return GNUNET_PQ_eval_prepared_non_select (pg->conn, - "gc_pending_payments", - params2); -} - - -/** - * Store payment. Used to begin a payment, not indicative - * that the payment actually was made. (That is done - * when we increment the account's lifetime.) - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param order_id order we create - * @param token claim token to use, NULL for none - * @param amount how much we asked for - * @return transaction status - */ -static enum SYNC_DB_QueryStatus -postgres_store_payment (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const char *order_id, - const struct TALER_ClaimTokenP *token, - const struct TALER_Amount *amount) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct TALER_ClaimTokenP tok; - struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_auto_from_type (&tok), - GNUNET_PQ_query_param_timestamp (&now), - TALER_PQ_query_param_amount (pg->conn, - amount), - GNUNET_PQ_query_param_end - }; - - if (NULL == token) - memset (&tok, 0, sizeof (tok)); - else - tok = *token; - check_connection (pg); - postgres_preflight (pg); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "payment_insert", - params); - switch (qs) - { - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); - return SYNC_DB_NO_RESULTS; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } -} - - -/** - * Closure for #payment_by_account_cb. - */ -struct PaymentIteratorContext -{ - /** - * Function to call on each result - */ - SYNC_DB_PaymentPendingIterator it; - - /** - * Closure for @e it. - */ - void *it_cls; - - /** - * Plugin context. - */ - struct PostgresClosure *pg; - - /** - * Query status to return. - */ - enum GNUNET_DB_QueryStatus qs; - -}; - - -/** - * Helper function for #postgres_lookup_pending_payments_by_account(). - * To be called with the results of a SELECT statement - * that has returned @a num_results results. - * - * @param cls closure of type `struct PaymentIteratorContext *` - * @param result the postgres result - * @param num_results the number of results in @a result - */ -static void -payment_by_account_cb (void *cls, - PGresult *result, - unsigned int num_results) -{ - struct PaymentIteratorContext *pic = cls; - - for (unsigned int i = 0; i < num_results; i++) - { - struct GNUNET_TIME_Timestamp timestamp; - char *order_id; - struct TALER_Amount amount; - struct TALER_ClaimTokenP token; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_timestamp ("timestamp", - &timestamp), - GNUNET_PQ_result_spec_string ("order_id", - &order_id), - GNUNET_PQ_result_spec_auto_from_type ("token", - &token), - TALER_PQ_result_spec_amount ("amount", - pic->pg->currency, - &amount), - GNUNET_PQ_result_spec_end - }; - - if (GNUNET_OK != - GNUNET_PQ_extract_result (result, - rs, - i)) - { - GNUNET_break (0); - pic->qs = GNUNET_DB_STATUS_HARD_ERROR; - return; - } - pic->qs = i + 1; - pic->it (pic->it_cls, - timestamp, - order_id, - &token, - &amount); - GNUNET_PQ_cleanup_result (rs); - } -} - - -/** - * Lookup pending payments by account. - * - * @param cls closure - * @param account_pub account to look for pending payments under - * @param it iterator to call on all pending payments - * @param it_cls closure for @a it - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -postgres_lookup_pending_payments_by_account (void *cls, - const struct - SYNC_AccountPublicKeyP *account_pub - , - SYNC_DB_PaymentPendingIterator it, - void *it_cls) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct PaymentIteratorContext pic = { - .it = it, - .it_cls = it_cls, - .pg = pg - }; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - postgres_preflight (pg); - qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, - "payments_select_by_account", - params, - &payment_by_account_cb, - &pic); - if (qs > 0) - return pic.qs; - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); - return qs; -} - - -/** - * Store backup. Only applicable for the FIRST backup under - * an @a account_pub. Use @e update_backup_TR to update an - * existing backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param account_sig signature affirming storage request - * @param backup_hash hash of @a backup - * @param backup_size number of bytes in @a backup - * @param backup raw data to backup - * @return transaction status - */ -static enum SYNC_DB_QueryStatus -postgres_store_backup (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const struct SYNC_AccountSignatureP *account_sig, - const struct GNUNET_HashCode *backup_hash, - size_t backup_size, - const void *backup) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_HashCode bh; - static struct GNUNET_HashCode no_previous_hash; - - check_connection (pg); - postgres_preflight (pg); - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_auto_from_type (account_sig), - GNUNET_PQ_query_param_auto_from_type (&no_previous_hash), - GNUNET_PQ_query_param_auto_from_type (backup_hash), - GNUNET_PQ_query_param_fixed_size (backup, - backup_size), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "backup_insert", - params); - } - switch (qs) - { - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_NO_RESULTS; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - case GNUNET_DB_STATUS_HARD_ERROR: - /* handle interesting case below */ - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* First, check if account exists */ - { - struct GNUNET_TIME_Timestamp ed; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("expiration_date", - &ed), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "account_select", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_PAYMENT_REQUIRED; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* handle interesting case below */ - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* account exists, check if existing backup conflicts */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("backup_hash", - &bh), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "backup_select_hash", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* original error must have been a hard error, oddly enough */ - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* handle interesting case below */ - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* had an existing backup, is it identical? */ - if (0 != GNUNET_memcmp (&bh, - backup_hash)) - /* previous conflicting backup exists */ - return SYNC_DB_OLD_BACKUP_MISMATCH; - /* backup identical to what was provided, no change */ - return SYNC_DB_NO_RESULTS; -} - - -/** - * Update backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param account_sig signature affirming storage request - * @param old_backup_hash hash of the previous backup (must match) - * @param backup_hash hash of @a backup - * @param backup_size number of bytes in @a backup - * @param backup raw data to backup - * @return transaction status - */ -static enum SYNC_DB_QueryStatus -postgres_update_backup (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const struct GNUNET_HashCode *old_backup_hash, - const struct SYNC_AccountSignatureP *account_sig, - const struct GNUNET_HashCode *backup_hash, - size_t backup_size, - const void *backup) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_HashCode bh; - - check_connection (pg); - postgres_preflight (pg); - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (backup_hash), - GNUNET_PQ_query_param_auto_from_type (account_sig), - GNUNET_PQ_query_param_auto_from_type (old_backup_hash), - GNUNET_PQ_query_param_fixed_size (backup, - backup_size), - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_auto_from_type (old_backup_hash), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "backup_update", - params); - } - switch (qs) - { - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* handle interesting case below */ - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* First, check if account exists */ - { - struct GNUNET_TIME_Timestamp ed; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("expiration_date", - &ed), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "account_select", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_PAYMENT_REQUIRED; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* handle interesting case below */ - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* account exists, check if existing backup conflicts */ - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("backup_hash", - &bh), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "backup_select_hash", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_OLD_BACKUP_MISSING; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* handle interesting case below */ - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* had an existing backup, is it identical? */ - if (0 == GNUNET_memcmp (&bh, - backup_hash)) - { - /* backup identical to what was provided, no change */ - return SYNC_DB_NO_RESULTS; - } - if (0 == GNUNET_memcmp (&bh, - old_backup_hash)) - /* all constraints seem satisfied, original error must - have been a hard error */ - return SYNC_DB_HARD_ERROR; - /* previous backup does not match old_backup_hash */ - return SYNC_DB_OLD_BACKUP_MISMATCH; -} - - -/** - * Lookup an account and associated backup meta data. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param[out] backup_hash set to hash of @a backup - * @return transaction status - */ -static enum SYNC_DB_QueryStatus -postgres_lookup_account (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - struct GNUNET_HashCode *backup_hash) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - - check_connection (pg); - postgres_preflight (pg); - { - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("backup_hash", - backup_hash), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "backup_select_hash", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - break; /* handle interesting case below */ - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - /* check if account exists */ - { - struct GNUNET_TIME_Timestamp expiration; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("expiration_date", - &expiration), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "account_select", - params, - rs); - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* indicates: no account */ - return SYNC_DB_PAYMENT_REQUIRED; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* indicates: no backup */ - return SYNC_DB_NO_RESULTS; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } -} - - -/** - * Obtain backup. - * - * @param cls closure - * @param account_pub account to store @a backup under - * @param[out] account_sig set to signature affirming storage request - * @param[out] prev_hash set to hash of previous @a backup, all zeros if none - * @param[out] backup_hash set to hash of @a backup - * @param[out] backup_size set to number of bytes in @a backup - * @param[out] backup set to raw data to backup, caller MUST FREE - */ -static enum SYNC_DB_QueryStatus -postgres_lookup_backup (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - struct SYNC_AccountSignatureP *account_sig, - struct GNUNET_HashCode *prev_hash, - struct GNUNET_HashCode *backup_hash, - size_t *backup_size, - void **backup) -{ - struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_auto_from_type ("account_sig", - account_sig), - GNUNET_PQ_result_spec_auto_from_type ("prev_hash", - prev_hash), - GNUNET_PQ_result_spec_auto_from_type ("backup_hash", - backup_hash), - GNUNET_PQ_result_spec_variable_size ("data", - backup, - backup_size), - GNUNET_PQ_result_spec_end - }; - - check_connection (pg); - postgres_preflight (pg); - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "backup_select", - params, - rs); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_NO_RESULTS; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } -} - - -/** - * Increment account lifetime. - * - * @param cls closure - * @param account_pub which account received a payment - * @param order_id order which was paid, must be unique and match pending payment - * @param lifetime for how long is the account now paid (increment) - * @return transaction status - */ -static enum SYNC_DB_QueryStatus -postgres_increment_lifetime (void *cls, - const struct SYNC_AccountPublicKeyP *account_pub, - const char *order_id, - struct GNUNET_TIME_Relative lifetime) -{ - struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Timestamp expiration; - enum GNUNET_DB_QueryStatus qs; - - check_connection (pg); - if (GNUNET_OK != - begin_transaction (pg, - "increment lifetime")) - { - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (order_id), - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "payment_done", - params); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - rollback (pg); - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - rollback (pg); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - rollback (pg); - return SYNC_DB_NO_RESULTS; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - } - - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_timestamp ("expiration_date", - &expiration), - GNUNET_PQ_result_spec_end - }; - - qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "account_select", - params, - rs); - } - - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - rollback (pg); - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - rollback (pg); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_timestamp (&expiration), - GNUNET_PQ_query_param_end - }; - - expiration = GNUNET_TIME_relative_to_timestamp (lifetime); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "account_insert", - params); - } - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - { - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_timestamp (&expiration), - GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_end - }; - - expiration = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (expiration.abs_time, - lifetime)); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "account_update", - params); - } - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - rollback (pg); - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - rollback (pg); - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_break (0); - rollback (pg); - return SYNC_DB_NO_RESULTS; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } - qs = commit_transaction (pg); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - return SYNC_DB_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - return SYNC_DB_SOFT_ERROR; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - return SYNC_DB_ONE_RESULT; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - return SYNC_DB_ONE_RESULT; - default: - GNUNET_break (0); - return SYNC_DB_HARD_ERROR; - } -} - - -/** - * Initialize tables. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure - */ -static enum GNUNET_GenericReturnValue -postgres_create_tables (void *cls) -{ - struct PostgresClosure *pc = cls; - struct GNUNET_PQ_Context *conn; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_execute ("SET search_path TO sync;"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - conn = GNUNET_PQ_connect_with_cfg (pc->cfg, - "syncdb-postgres", - "sync-", - es, - NULL); - if (NULL == conn) - return GNUNET_SYSERR; - GNUNET_PQ_disconnect (conn); - return GNUNET_OK; -} - - -/** - * Initialize Postgres database subsystem. - * - * @param cls a configuration instance - * @return NULL on error, otherwise a `struct TALER_SYNCDB_Plugin` - */ -void * -libsync_plugin_db_postgres_init (void *cls); - -/* make compiler happy */ -void * -libsync_plugin_db_postgres_init (void *cls) -{ - struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct PostgresClosure *pg; - struct SYNC_DatabasePlugin *plugin; - - pg = GNUNET_new (struct PostgresClosure); - pg->cfg = cfg; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "syncdb-postgres", - "SQL_DIR", - &pg->sql_dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "syncdb-postgres", - "SQL_DIR"); - GNUNET_free (pg); - return NULL; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "sync", - "CURRENCY", - &pg->currency)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "sync", - "CURRENCY"); - GNUNET_free (pg->sql_dir); - GNUNET_free (pg); - return NULL; - } - plugin = GNUNET_new (struct SYNC_DatabasePlugin); - plugin->cls = pg; - plugin->create_tables = &postgres_create_tables; - plugin->drop_tables = &postgres_drop_tables; - plugin->preflight = &postgres_preflight; - plugin->gc = &postgres_gc; - plugin->store_payment_TR = &postgres_store_payment; - plugin->lookup_pending_payments_by_account_TR = - &postgres_lookup_pending_payments_by_account; - plugin->store_backup_TR = &postgres_store_backup; - plugin->lookup_account_TR = &postgres_lookup_account; - plugin->lookup_backup_TR = &postgres_lookup_backup; - plugin->update_backup_TR = &postgres_update_backup; - plugin->increment_lifetime_TR = &postgres_increment_lifetime; - return plugin; -} - - -/** - * Shutdown Postgres database subsystem. - * - * @param cls a `struct SYNC_DB_Plugin` - * @return NULL (always) - */ -void * -libsync_plugin_db_postgres_done (void *cls); - -/* make compiler happy */ -void * -libsync_plugin_db_postgres_done (void *cls) -{ - struct SYNC_DatabasePlugin *plugin = cls; - struct PostgresClosure *pg = plugin->cls; - - GNUNET_PQ_disconnect (pg->conn); - GNUNET_free (pg->currency); - GNUNET_free (pg->sql_dir); - GNUNET_free (pg); - GNUNET_free (plugin); - return NULL; -} - - -/* end of plugin_syncdb_postgres.c */ diff --git a/src/syncdb/sync-dbinit.c b/src/syncdb/sync-dbinit.c @@ -20,8 +20,8 @@ */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> -#include "sync_util.h" -#include "sync_database_lib.h" +#include "sync/sync_util.h" +#include "sync/sync_database_lib.h" /** @@ -54,30 +54,28 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { - struct SYNC_DatabasePlugin *plugin; - - if (NULL == - (plugin = SYNC_DB_plugin_load (cfg, - true))) + if (GNUNET_OK != + SYNCDB_init (cfg, + true)) { fprintf (stderr, - "Failed to initialize database plugin.\n"); + "Failed to initialize database.\n"); global_ret = EXIT_NOTINSTALLED; return; } if (reset_db) { - if (GNUNET_OK != plugin->drop_tables (plugin->cls)) + if (GNUNET_OK != SYNCDB_drop_tables ()) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n"); } } if (GNUNET_OK != - plugin->create_tables (plugin->cls)) + SYNCDB_create_tables ()) { global_ret = EXIT_FAILURE; - SYNC_DB_plugin_unload (plugin); + SYNCDB_fini (); return; } if (gc_db) @@ -91,16 +89,15 @@ run (void *cls, GNUNET_TIME_UNIT_YEARS, 6)); if (0 > - plugin->gc (plugin->cls, - now, - ancient)) + SYNCDB_gc (now, + ancient)) { fprintf (stderr, "Garbage collection failed!\n"); global_ret = EXIT_FAILURE; } } - SYNC_DB_plugin_unload (plugin); + SYNCDB_fini (); } diff --git a/src/syncdb/sync_db_plugin.c b/src/syncdb/sync_db_plugin.c @@ -20,8 +20,8 @@ * @author Sree Harsha Totakura <sreeharsha@totakura.in> */ #include "platform.h" -#include "sync_util.h" -#include "sync_database_lib.h" +#include "sync/sync_util.h" +#include "sync/sync_database_lib.h" #include <ltdl.h> diff --git a/src/syncdb/syncdb_create_tables.c b/src/syncdb/syncdb_create_tables.c @@ -0,0 +1,45 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_create_tables.c + * @brief create sync database tables + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum GNUNET_GenericReturnValue +SYNCDB_create_tables (void) +{ + struct GNUNET_PQ_Context *conn; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "syncdb-postgres", + "sync-", + es, + NULL); + if (NULL == conn) + return GNUNET_SYSERR; + GNUNET_PQ_disconnect (conn); + return GNUNET_OK; +} + + +/* end of syncdb_create_tables.c */ diff --git a/src/syncdb/syncdb_drop_tables.c b/src/syncdb/syncdb_drop_tables.c @@ -0,0 +1,49 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_drop_tables.c + * @brief drop sync database tables + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum GNUNET_GenericReturnValue +SYNCDB_drop_tables (void) +{ + struct GNUNET_PQ_Context *conn; + enum GNUNET_GenericReturnValue ret; + + if (NULL != pg->conn) + { + GNUNET_PQ_disconnect (pg->conn); + pg->conn = NULL; + } + conn = GNUNET_PQ_connect_with_cfg (pg->cfg, + "syncdb-postgres", + NULL, + NULL, + NULL); + if (NULL == conn) + return GNUNET_SYSERR; + ret = GNUNET_PQ_exec_sql (conn, + "drop"); + GNUNET_PQ_disconnect (conn); + return ret; +} + + +/* end of syncdb_drop_tables.c */ diff --git a/src/syncdb/syncdb_gc.c b/src/syncdb/syncdb_gc.c @@ -0,0 +1,60 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_gc.c + * @brief garbage collection for sync database + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum GNUNET_DB_QueryStatus +SYNCDB_gc (struct GNUNET_TIME_Absolute expire_backups, + struct GNUNET_TIME_Absolute expire_pending_payments) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_absolute_time (&expire_backups), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_QueryParam params2[] = { + GNUNET_PQ_query_param_absolute_time (&expire_pending_payments), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + SYNCDB_preflight (); + PREPARE ("gc_accounts", + "DELETE FROM accounts " + "WHERE" + " expiration_date < $1;"); + PREPARE ("gc_pending_payments", + "DELETE FROM payments " + "WHERE" + " paid=FALSE" + " AND" + " timestamp < $1;"); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_accounts", + params); + if (qs < 0) + return qs; + return GNUNET_PQ_eval_prepared_non_select (pg->conn, + "gc_pending_payments", + params2); +} + + +/* end of syncdb_gc.c */ diff --git a/src/syncdb/syncdb_increment_lifetime_TR.c b/src/syncdb/syncdb_increment_lifetime_TR.c @@ -0,0 +1,198 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_increment_lifetime_TR.c + * @brief increment account lifetime after payment + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_increment_lifetime_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const char *order_id, + struct GNUNET_TIME_Relative lifetime) +{ + struct GNUNET_TIME_Timestamp expiration; + enum GNUNET_DB_QueryStatus qs; + + if (GNUNET_OK != + begin_transaction ("increment lifetime")) + { + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("increment_lifetime_payment_done", + "UPDATE payments " + "SET" + " paid=TRUE " + "WHERE" + " order_id=$1" + " AND" + " account_pub=$2" + " AND" + " paid=FALSE;"); + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "increment_lifetime_payment_done", + params); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + rollback (); + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + rollback (); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + rollback (); + return SYNC_DB_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + } + + PREPARE ("increment_lifetime_account_select", + "SELECT" + " expiration_date " + "FROM" + " accounts " + "WHERE" + " account_pub=$1;"); + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_timestamp ("expiration_date", + &expiration), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "increment_lifetime_account_select", + params, + rs); + } + + PREPARE ("increment_lifetime_account_insert", + "INSERT INTO accounts " + "(account_pub" + ",expiration_date" + ") VALUES " + "($1,$2);"); + + PREPARE ("increment_lifetime_account_update", + "UPDATE accounts " + "SET" + " expiration_date=$1 " + "WHERE" + " account_pub=$2;"); + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (); + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + rollback (); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_timestamp (&expiration), + GNUNET_PQ_query_param_end + }; + + expiration = GNUNET_TIME_relative_to_timestamp (lifetime); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "increment_lifetime_account_insert", + params); + } + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_timestamp (&expiration), + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + + expiration = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add (expiration.abs_time, + lifetime)); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "increment_lifetime_account_update", + params); + } + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + rollback (); + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + rollback (); + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + rollback (); + return SYNC_DB_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + qs = commit_transaction (); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_ONE_RESULT; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } +} + + +/* end of syncdb_increment_lifetime_TR.c */ diff --git a/src/syncdb/syncdb_lookup_account_TR.c b/src/syncdb/syncdb_lookup_account_TR.c @@ -0,0 +1,115 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_lookup_account_TR.c + * @brief lookup account and backup metadata + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_lookup_account_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + struct GNUNET_HashCode *backup_hash) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + + SYNCDB_preflight (); + + PREPARE ("lookup_account_backup_select_hash", + "SELECT " + " backup_hash " + "FROM" + " backups " + "WHERE" + " account_pub=$1;"); + + { + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("backup_hash", + backup_hash), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_account_backup_select_hash", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + break; /* handle interesting case below */ + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("lookup_account_account_select", + "SELECT" + " expiration_date " + "FROM" + " accounts " + "WHERE" + " account_pub=$1;"); + + /* check if account exists */ + { + struct GNUNET_TIME_Timestamp expiration; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("expiration_date", + &expiration), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "lookup_account_account_select", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* indicates: no account */ + return SYNC_DB_PAYMENT_REQUIRED; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* indicates: no backup */ + return SYNC_DB_NO_RESULTS; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } +} + + +/* end of syncdb_lookup_account_TR.c */ diff --git a/src/syncdb/syncdb_lookup_backup_TR.c b/src/syncdb/syncdb_lookup_backup_TR.c @@ -0,0 +1,84 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_lookup_backup_TR.c + * @brief obtain backup data + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_lookup_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + struct SYNC_AccountSignatureP *account_sig, + struct GNUNET_HashCode *prev_hash, + struct GNUNET_HashCode *backup_hash, + size_t *backup_size, + void **backup) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("account_sig", + account_sig), + GNUNET_PQ_result_spec_auto_from_type ("prev_hash", + prev_hash), + GNUNET_PQ_result_spec_auto_from_type ("backup_hash", + backup_hash), + GNUNET_PQ_result_spec_variable_size ("data", + backup, + backup_size), + GNUNET_PQ_result_spec_end + }; + + SYNCDB_preflight (); + PREPARE ("backup_select", + "SELECT " + " account_sig" + ",prev_hash" + ",backup_hash" + ",data " + "FROM" + " backups " + "WHERE" + " account_pub=$1;"); + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "backup_select", + params, + rs); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } +} + + +/* end of syncdb_lookup_backup_TR.c */ diff --git a/src/syncdb/syncdb_lookup_pending_payments_by_account_TR.c b/src/syncdb/syncdb_lookup_pending_payments_by_account_TR.c @@ -0,0 +1,142 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_lookup_pending_payments_by_account_TR.c + * @brief lookup pending payments by account + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +/** + * Closure for #payment_by_account_cb. + */ +struct PaymentIteratorContext +{ + /** + * Function to call on each result + */ + SYNC_DB_PaymentPendingIterator it; + + /** + * Closure for @e it. + */ + void *it_cls; + + /** + * Query status to return. + */ + enum GNUNET_DB_QueryStatus qs; + +}; + + +/** + * Helper function for #SYNCDB_lookup_pending_payments_by_account_TR(). + * To be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct PaymentIteratorContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +payment_by_account_cb (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct PaymentIteratorContext *pic = cls; + + for (unsigned int i = 0; i < num_results; i++) + { + struct GNUNET_TIME_Timestamp timestamp; + char *order_id; + struct TALER_Amount amount; + struct TALER_ClaimTokenP token; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_timestamp ("timestamp", + &timestamp), + GNUNET_PQ_result_spec_string ("order_id", + &order_id), + GNUNET_PQ_result_spec_auto_from_type ("token", + &token), + TALER_PQ_result_spec_amount ("amount", + pg->currency, + &amount), + GNUNET_PQ_result_spec_end + }; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + pic->qs = GNUNET_DB_STATUS_HARD_ERROR; + return; + } + pic->qs = i + 1; + pic->it (pic->it_cls, + timestamp, + order_id, + &token, + &amount); + GNUNET_PQ_cleanup_result (rs); + } +} + + +enum GNUNET_DB_QueryStatus +SYNCDB_lookup_pending_payments_by_account_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + SYNC_DB_PaymentPendingIterator it, + void *it_cls) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct PaymentIteratorContext pic = { + .it = it, + .it_cls = it_cls + }; + enum GNUNET_DB_QueryStatus qs; + + SYNCDB_preflight (); + PREPARE ("payments_select_by_account", + "SELECT" + " timestamp" + ",order_id" + ",token" + ",amount" + " FROM payments" + " WHERE" + " paid=FALSE" + " AND" + " account_pub=$1;"); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "payments_select_by_account", + params, + &payment_by_account_cb, + &pic); + if (qs > 0) + return pic.qs; + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); + return qs; +} + + +/* end of syncdb_lookup_pending_payments_by_account_TR.c */ diff --git a/src/syncdb/syncdb_pg.c b/src/syncdb/syncdb_pg.c @@ -0,0 +1,150 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_pg.c + * @brief shared database state and helpers for sync postgres + * @author Christian Grothoff + */ +#include "syncdb_pg.h" +#include "sync/sync_util.h" + + +/** + * Global database closure. + */ +struct PostgresClosure *pg; + + +enum GNUNET_GenericReturnValue +begin_transaction (const char *name) +{ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("START TRANSACTION ISOLATION LEVEL SERIALIZABLE"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + SYNCDB_preflight (); + pg->transaction_name = name; + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to start transaction\n"); + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +void +rollback (void) +{ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("ROLLBACK"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (GNUNET_OK != + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + TALER_LOG_ERROR ("Failed to rollback transaction\n"); + GNUNET_break (0); + } + pg->transaction_name = NULL; +} + + +enum GNUNET_DB_QueryStatus +commit_transaction (void) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_PQ_QueryParam no_params[] = { + GNUNET_PQ_query_param_end + }; + + PREPARE ("do_commit", + "COMMIT"); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "do_commit", + no_params); + pg->transaction_name = NULL; + return qs; +} + + +enum GNUNET_GenericReturnValue +SYNCDB_init (const struct GNUNET_CONFIGURATION_Handle *cfg, + bool skip_preflight) +{ + pg = GNUNET_new (struct PostgresClosure); + pg->cfg = cfg; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "syncdb-postgres", + "SQL_DIR", + &pg->sql_dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "syncdb-postgres", + "SQL_DIR"); + GNUNET_free (pg); + pg = NULL; + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "sync", + "CURRENCY", + &pg->currency)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "sync", + "CURRENCY"); + GNUNET_free (pg->sql_dir); + GNUNET_free (pg); + pg = NULL; + return GNUNET_SYSERR; + } + if ( (! skip_preflight) && + (GNUNET_OK != + SYNCDB_preflight ()) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database not ready. Try running sync-dbinit!\n"); + SYNCDB_fini (); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +void +SYNCDB_fini (void) +{ + if (NULL == pg) + return; + if (NULL != pg->conn) + GNUNET_PQ_disconnect (pg->conn); + GNUNET_free (pg->currency); + GNUNET_free (pg->sql_dir); + GNUNET_free (pg); + pg = NULL; +} + + +/* end of syncdb_pg.c */ diff --git a/src/syncdb/syncdb_preflight.c b/src/syncdb/syncdb_preflight.c @@ -0,0 +1,114 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_preflight.c + * @brief preflight check for sync database + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +static enum GNUNET_GenericReturnValue +internal_setup (void) +{ + if (NULL == pg->conn) + { +#if AUTO_EXPLAIN + /* Enable verbose logging to see where queries do not + properly use indices */ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"), + GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"), + /* https://wiki.postgresql.org/wiki/Serializable suggests to really + force the default to 'serializable' if SSI is to be used. */ + GNUNET_PQ_make_try_execute ( + "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), + GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), + GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#else + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO sync;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; +#endif + struct GNUNET_PQ_Context *db_conn; + + db_conn = GNUNET_PQ_connect_with_cfg2 (pg->cfg, + "syncdb-postgres", + "sync-", + es, + NULL, + GNUNET_PQ_FLAG_CHECK_CURRENT); + if (NULL == db_conn) + return GNUNET_SYSERR; + pg->conn = db_conn; + pg->prep_gen++; + } + if (NULL == pg->transaction_name) + GNUNET_PQ_reconnect_if_down (pg->conn); + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +SYNCDB_preflight (void) +{ + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("ROLLBACK"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (NULL == pg->conn) + { + if (GNUNET_OK != + internal_setup ()) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to ensure DB is initialized\n"); + return GNUNET_SYSERR; + } + } + else + { + GNUNET_PQ_reconnect_if_down (pg->conn); + } + if (NULL == pg->transaction_name) + return GNUNET_OK; /* all good */ + if (GNUNET_OK == + GNUNET_PQ_exec_statements (pg->conn, + es)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check rolled back transaction `%s'!\n", + pg->transaction_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check failed to rollback transaction `%s'!\n", + pg->transaction_name); + } + pg->transaction_name = NULL; + return GNUNET_NO; +} + + +/* end of syncdb_preflight.c */ diff --git a/src/syncdb/syncdb_store_backup_TR.c b/src/syncdb/syncdb_store_backup_TR.c @@ -0,0 +1,177 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_store_backup_TR.c + * @brief store first backup + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_store_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const struct SYNC_AccountSignatureP *account_sig, + const struct GNUNET_HashCode *backup_hash, + size_t backup_size, + const void *backup) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_HashCode bh; + static struct GNUNET_HashCode no_previous_hash; + + SYNCDB_preflight (); + + PREPARE ("store_backup_backup_insert", + "INSERT INTO backups " + "(account_pub" + ",account_sig" + ",prev_hash" + ",backup_hash" + ",data" + ") VALUES " + "($1,$2,$3,$4,$5);"); + + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_auto_from_type (account_sig), + GNUNET_PQ_query_param_auto_from_type (&no_previous_hash), + GNUNET_PQ_query_param_auto_from_type (backup_hash), + GNUNET_PQ_query_param_fixed_size (backup, + backup_size), + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "store_backup_backup_insert", + params); + } + switch (qs) + { + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + case GNUNET_DB_STATUS_HARD_ERROR: + /* handle interesting case below */ + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("store_backup_account_select", + "SELECT" + " expiration_date " + "FROM" + " accounts " + "WHERE" + " account_pub=$1;"); + + /* First, check if account exists */ + { + struct GNUNET_TIME_Timestamp ed; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("expiration_date", + &ed), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "store_backup_account_select", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_PAYMENT_REQUIRED; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* handle interesting case below */ + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("store_backup_backup_select_hash", + "SELECT " + " backup_hash " + "FROM" + " backups " + "WHERE" + " account_pub=$1;"); + + + /* account exists, check if existing backup conflicts */ + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("backup_hash", + &bh), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "store_backup_backup_select_hash", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* original error must have been a hard error, oddly enough */ + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* handle interesting case below */ + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + /* had an existing backup, is it identical? */ + if (0 != GNUNET_memcmp (&bh, + backup_hash)) + /* previous conflicting backup exists */ + return SYNC_DB_OLD_BACKUP_MISMATCH; + /* backup identical to what was provided, no change */ + return SYNC_DB_NO_RESULTS; +} + + +/* end of syncdb_store_backup_TR.c */ diff --git a/src/syncdb/syncdb_store_payment_TR.c b/src/syncdb/syncdb_store_payment_TR.c @@ -0,0 +1,81 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_store_payment_TR.c + * @brief store payment for sync database + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_store_payment_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const char *order_id, + const struct TALER_ClaimTokenP *token, + const struct TALER_Amount *amount) +{ + enum GNUNET_DB_QueryStatus qs; + struct TALER_ClaimTokenP tok; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_string (order_id), + GNUNET_PQ_query_param_auto_from_type (&tok), + GNUNET_PQ_query_param_timestamp (&now), + TALER_PQ_query_param_amount (pg->conn, + amount), + GNUNET_PQ_query_param_end + }; + + if (NULL == token) + memset (&tok, 0, sizeof (tok)); + else + tok = *token; + SYNCDB_preflight (); + PREPARE ("payment_insert", + "INSERT INTO payments " + "(account_pub" + ",order_id" + ",token" + ",timestamp" + ",amount" + ") VALUES " + "($1,$2,$3,$4,$5);"); + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "payment_insert", + params); + switch (qs) + { + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return SYNC_DB_NO_RESULTS; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } +} + + +/* end of syncdb_store_payment_TR.c */ diff --git a/src/syncdb/syncdb_update_backup_TR.c b/src/syncdb/syncdb_update_backup_TR.c @@ -0,0 +1,184 @@ +/* + This file is part of TALER + (C) 2014--2022 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER 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 + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file syncdb/syncdb_update_backup_TR.c + * @brief update existing backup + * @author Christian Grothoff + */ +#include "syncdb_pg.h" + + +enum SYNC_DB_QueryStatus +SYNCDB_update_backup_TR ( + const struct SYNC_AccountPublicKeyP *account_pub, + const struct GNUNET_HashCode *old_backup_hash, + const struct SYNC_AccountSignatureP *account_sig, + const struct GNUNET_HashCode *backup_hash, + size_t backup_size, + const void *backup) +{ + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_HashCode bh; + + SYNCDB_preflight (); + PREPARE ("backup_update", + "UPDATE backups " + " SET" + " backup_hash=$1" + ",account_sig=$2" + ",prev_hash=$3" + ",data=$4" + " WHERE" + " account_pub=$5" + " AND" + " backup_hash=$6;"); + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (backup_hash), + GNUNET_PQ_query_param_auto_from_type (account_sig), + GNUNET_PQ_query_param_auto_from_type (old_backup_hash), + GNUNET_PQ_query_param_fixed_size (backup, + backup_size), + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_auto_from_type (old_backup_hash), + GNUNET_PQ_query_param_end + }; + + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "backup_update", + params); + } + switch (qs) + { + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* handle interesting case below */ + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return SYNC_DB_ONE_RESULT; + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("update_backup_account_select", + "SELECT" + " expiration_date " + "FROM" + " accounts " + "WHERE" + " account_pub=$1;"); + + /* First, check if account exists */ + { + struct GNUNET_TIME_Timestamp ed; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("expiration_date", + &ed), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "update_backup_account_select", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_PAYMENT_REQUIRED; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* handle interesting case below */ + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + PREPARE ("update_backup_backup_select_hash", + "SELECT " + " backup_hash " + "FROM" + " backups " + "WHERE" + " account_pub=$1;"); + + /* account exists, check if existing backup conflicts */ + { + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_auto_from_type ("backup_hash", + &bh), + GNUNET_PQ_result_spec_end + }; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "update_backup_backup_select_hash", + params, + rs); + } + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + return SYNC_DB_HARD_ERROR; + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return SYNC_DB_SOFT_ERROR; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + return SYNC_DB_OLD_BACKUP_MISSING; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* handle interesting case below */ + break; + default: + GNUNET_break (0); + return SYNC_DB_HARD_ERROR; + } + + /* had an existing backup, is it identical? */ + if (0 == GNUNET_memcmp (&bh, + backup_hash)) + { + /* backup identical to what was provided, no change */ + return SYNC_DB_NO_RESULTS; + } + if (0 == GNUNET_memcmp (&bh, + old_backup_hash)) + /* all constraints seem satisfied, original error must + have been a hard error */ + return SYNC_DB_HARD_ERROR; + /* previous backup does not match old_backup_hash */ + return SYNC_DB_OLD_BACKUP_MISMATCH; +} + + +/* end of syncdb_update_backup_TR.c */ diff --git a/src/syncdb/test_sync_db.c b/src/syncdb/test_sync_db.c @@ -15,16 +15,15 @@ */ /** * @file sync/test_sync_db.c - * @brief testcase for sync postgres db plugin + * @brief testcase for sync postgres db * @author Christian Grothoff */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> #include <taler/taler_util.h> -#include "sync_service.h" -#include "sync_database_plugin.h" -#include "sync_database_lib.h" -#include "sync_util.h" +#include "sync/sync_service.h" +#include "sync/sync_database_lib.h" +#include "sync/sync_util.h" #define FAILIF(cond) \ @@ -44,11 +43,6 @@ */ static int result; -/** - * Handle to the plugin we are testing. - */ -static struct SYNC_DatabasePlugin *plugin; - /** * Function called on all pending payments for an account. @@ -95,26 +89,27 @@ run (void *cls) size_t bs; void *b = NULL; - if (NULL == (plugin = SYNC_DB_plugin_load (cfg, - true))) + if (GNUNET_OK != + SYNCDB_init (cfg, + true)) { result = 77; return; } if (GNUNET_OK != - plugin->drop_tables (plugin->cls)) + SYNCDB_drop_tables ()) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Dropping tables failed\n"); } if (GNUNET_OK != - plugin->create_tables (plugin->cls)) + SYNCDB_create_tables ()) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating tables failed\n"); } GNUNET_assert (GNUNET_OK == - plugin->preflight (plugin->cls)); + SYNCDB_preflight ()); memset (&account_pub, 1, sizeof (account_pub)); memset (&account_sig, 2, sizeof (account_sig)); memset (&token, 3, sizeof (token)); @@ -125,68 +120,59 @@ run (void *cls) TALER_string_to_amount ("EUR:1", &amount)); FAILIF (SYNC_DB_ONE_RESULT != - plugin->store_payment_TR (plugin->cls, - &account_pub, - "fake-order", - &token, - &amount)); + SYNCDB_store_payment_TR (&account_pub, + "fake-order", + &token, + &amount)); + FAILIF (SYNC_DB_ONE_RESULT != + SYNCDB_increment_lifetime_TR (&account_pub, + "fake-order", + GNUNET_TIME_UNIT_MINUTES)); FAILIF (SYNC_DB_ONE_RESULT != - plugin->increment_lifetime_TR (plugin->cls, - &account_pub, - "fake-order", - GNUNET_TIME_UNIT_MINUTES)); + SYNCDB_store_backup_TR (&account_pub, + &account_sig, + &h, + 4, + "data")); + FAILIF (SYNC_DB_NO_RESULTS != + SYNCDB_store_backup_TR (&account_pub, + &account_sig, + &h, + 4, + "data")); FAILIF (SYNC_DB_ONE_RESULT != - plugin->store_backup_TR (plugin->cls, - &account_pub, + SYNCDB_update_backup_TR (&account_pub, + &h, &account_sig, + &h2, + 4, + "DATA")); + FAILIF (SYNC_DB_OLD_BACKUP_MISMATCH != + SYNCDB_update_backup_TR (&account_pub, &h, + &account_sig, + &h3, 4, - "data")); + "ATAD")); FAILIF (SYNC_DB_NO_RESULTS != - plugin->store_backup_TR (plugin->cls, - &account_pub, - &account_sig, + SYNCDB_update_backup_TR (&account_pub, &h, + &account_sig, + &h2, 4, - "data")); + "DATA")); FAILIF (SYNC_DB_ONE_RESULT != - plugin->update_backup_TR (plugin->cls, - &account_pub, - &h, - &account_sig, - &h2, - 4, - "DATA")); - FAILIF (SYNC_DB_OLD_BACKUP_MISMATCH != - plugin->update_backup_TR (plugin->cls, - &account_pub, - &h, - &account_sig, - &h3, - 4, - "ATAD")); - FAILIF (SYNC_DB_NO_RESULTS != - plugin->update_backup_TR (plugin->cls, - &account_pub, - &h, - &account_sig, - &h2, - 4, - "DATA")); - FAILIF (SYNC_DB_ONE_RESULT != - plugin->lookup_account_TR (plugin->cls, - &account_pub, - &r)); + SYNCDB_lookup_account_TR (&account_pub, + &r)); FAILIF (0 != GNUNET_memcmp (&r, &h2)); FAILIF (SYNC_DB_ONE_RESULT != - plugin->lookup_backup_TR (plugin->cls, - &account_pub, - &account_sig2, - &r, - &r2, - &bs, - &b)); + SYNCDB_lookup_backup_TR (&account_pub, + &account_sig2, + &r, + &r2, + &bs, + &b)); FAILIF (0 != GNUNET_memcmp (&r, &h)); FAILIF (0 != GNUNET_memcmp (&r2, @@ -200,64 +186,55 @@ run (void *cls) GNUNET_free (b); b = NULL; FAILIF (0 != - plugin->lookup_pending_payments_by_account_TR (plugin->cls, - &account_pub, - &payment_it, - NULL)); + SYNCDB_lookup_pending_payments_by_account_TR (&account_pub, + &payment_it, + NULL)); memset (&account_pub, 2, sizeof (account_pub)); FAILIF (SYNC_DB_ONE_RESULT != - plugin->store_payment_TR (plugin->cls, - &account_pub, - "fake-order-2", - &token, - &amount)); + SYNCDB_store_payment_TR (&account_pub, + "fake-order-2", + &token, + &amount)); FAILIF (1 != - plugin->lookup_pending_payments_by_account_TR (plugin->cls, - &account_pub, - &payment_it, - NULL)); + SYNCDB_lookup_pending_payments_by_account_TR (&account_pub, + &payment_it, + NULL)); FAILIF (SYNC_DB_PAYMENT_REQUIRED != - plugin->store_backup_TR (plugin->cls, - &account_pub, - &account_sig, - &h, - 4, - "data")); + SYNCDB_store_backup_TR (&account_pub, + &account_sig, + &h, + 4, + "data")); FAILIF (SYNC_DB_ONE_RESULT != - plugin->increment_lifetime_TR (plugin->cls, - &account_pub, - "fake-order-2", - GNUNET_TIME_UNIT_MINUTES)); + SYNCDB_increment_lifetime_TR (&account_pub, + "fake-order-2", + GNUNET_TIME_UNIT_MINUTES)); FAILIF (SYNC_DB_OLD_BACKUP_MISSING != - plugin->update_backup_TR (plugin->cls, - &account_pub, - &h, - &account_sig, - &h2, - 4, - "DATA")); + SYNCDB_update_backup_TR (&account_pub, + &h, + &account_sig, + &h2, + 4, + "DATA")); ts = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS); FAILIF (0 > - plugin->gc (plugin->cls, - ts, - ts)); + SYNCDB_gc (ts, + ts)); memset (&account_pub, 1, sizeof (account_pub)); FAILIF (SYNC_DB_NO_RESULTS != - plugin->lookup_backup_TR (plugin->cls, - &account_pub, - &account_sig2, - &r, - &r2, - &bs, - &b)); + SYNCDB_lookup_backup_TR (&account_pub, + &account_sig2, + &r, + &r2, + &bs, + &b)); result = 0; drop: GNUNET_free (b); GNUNET_break (GNUNET_OK == - plugin->drop_tables (plugin->cls)); - SYNC_DB_plugin_unload (plugin); - plugin = NULL; + SYNCDB_drop_tables ()); + SYNCDB_fini (); } diff --git a/src/testing/test_sync_api.c b/src/testing/test_sync_api.c @@ -33,8 +33,8 @@ #include <taler/taler_testing_lib.h> #include <taler/taler_merchant_testing_lib.h> #include <taler/taler_error_codes.h> -#include "sync_service.h" -#include "sync_testing_lib.h" +#include "sync/sync_service.h" +#include "sync/sync_testing_lib.h" /** * Configuration file we use. One (big) configuration is used diff --git a/src/testing/testing_api_cmd_backup_download.c b/src/testing/testing_api_cmd_backup_download.c @@ -22,8 +22,8 @@ * @author Christian Grothoff */ #include "platform.h" -#include "sync_service.h" -#include "sync_testing_lib.h" +#include "sync/sync_service.h" +#include "sync/sync_testing_lib.h" #include <taler/taler_util.h> #include <taler/taler_testing_lib.h> diff --git a/src/testing/testing_api_cmd_backup_upload.c b/src/testing/testing_api_cmd_backup_upload.c @@ -22,12 +22,12 @@ * @author Christian Grothoff */ #include "platform.h" -#include "sync_service.h" -#include "sync_testing_lib.h" +#include "sync/sync_service.h" +#include "sync/sync_testing_lib.h" #include <taler/taler_util.h> #include <taler/taler_testing_lib.h> #include <taler/taler_merchant_service.h> -#include "sync_testing_lib.h" +#include "sync/sync_testing_lib.h" /** * State for a "backup upload" CMD. diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c @@ -22,7 +22,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "sync_testing_lib.h" +#include "sync/sync_testing_lib.h" SYNC_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_IMPL_SIMPLE_TRAIT) diff --git a/src/util/os_installation.c b/src/util/os_installation.c @@ -25,7 +25,7 @@ */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> -#include "sync_util.h" +#include "sync/sync_util.h" /** diff --git a/src/util/sync-config.c b/src/util/sync-config.c @@ -24,7 +24,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "sync_util.h" +#include "sync/sync_util.h" /**