diff --git a/INSTALL b/INSTALL
index a1e89e18a..209984075 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
Installation Instructions
*************************
-Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
@@ -12,8 +12,8 @@ without warranty of any kind.
Basic Installation
==================
- Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package. The following
+ Briefly, the shell command `./configure && make && make install'
+should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
@@ -309,9 +309,10 @@ causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug. Until the bug is fixed you can use this workaround:
+an Autoconf limitation. Until the limitation is lifted, you can use
+this workaround:
- CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
@@ -367,4 +368,3 @@ operates.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
-
diff --git a/configure.ac b/configure.ac
index 5835cb635..f69bcefd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,6 +65,13 @@ AS_IF([test $libgnunetutil != 1],
*** ]])])
+TALER_LIB_LDFLAGS="-export-dynamic -no-undefined"
+TALER_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined"
+
+AC_SUBST(TALER_LIB_LDFLAGS)
+AC_SUBST(TALER_PLUGIN_LDFLAGS)
+
+
# check for libmicrohttpd
microhttpd=0
AC_MSG_CHECKING([for microhttpd])
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 3569bd782..e46583989 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -99,4 +99,16 @@ TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
struct TALER_Amount *denom);
+/**
+ * Get the path to a specific Taler installation directory or, with
+ * #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation
+ * directory.
+ *
+ * @param dirkind what kind of directory is desired?
+ * @return a pointer to the dir path (to be freed by the caller)
+ */
+char *
+TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind);
+
+
#endif
diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am
index 2436d7f37..c4f99af63 100644
--- a/src/mint/Makefile.am
+++ b/src/mint/Makefile.am
@@ -1,18 +1,31 @@
# This Makefile.am is in the public domain
AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS)
+plugindir = $(libdir)/taler
+
+plugin_LTLIBRARIES = \
+ libtaler_plugin_mintdb_postgres.la
+
+libtaler_plugin_mintdb_postgres_la_SOURCES = \
+ plugin_mintdb_postgres.c
+libtaler_plugin_mintdb_postgres_la_LIBADD = \
+ $(LTLIBINTL)
+libtaler_plugin_mintdb_postgres_la_LDFLAGS = \
+ $(TALER_PLUGIN_LDFLAGS) \
+ -lpq \
+ -lgnunetutil
+
lib_LTLIBRARIES = \
libtalermint_common.la
-# Note: mint_db.c should become a plugin soon! (#3608)
libtalermint_common_la_SOURCES = \
key_io.c key_io.h \
- mint_db.c
+ plugin.c plugin.h \
+ taler_mintdb_plugin.h
libtalermint_common_la_LIBADD = \
$(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil \
- -lpq
+ -lgnunetutil
libtalermint_common_la_LDFLAGS = \
$(POSTGRESQL_LDFLAGS) \
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
deleted file mode 100644
index d11ee8fe9..000000000
--- a/src/mint/mint_db.h
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
-
- 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, If not, see
-*/
-/**
- * @file mint/mint_db.h
- * @brief Low-level (statement-level) database access for the mint
- * @author Florian Dold
- * @author Christian Grothoff
- */
-#ifndef MINT_DB_H
-#define MINT_DB_H
-
-#include
-#include
-#include
-#include "taler_util.h"
-
-#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
-
-/**
- * Initialize database subsystem.
- *
- * @param connection_cfg configuration for the DB
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_init (const char *connection_cfg);
-
-
-/**
- * Get the thread-local database-handle.
- * Connect to the db if the connection does not exist yet.
- *
- * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
- * database default one
- * @param the database connection, or NULL on error
- */
-PGconn *
-TALER_MINT_DB_get_connection (int temporary);
-
-
-/**
- * Drop the temporary taler schema. This is only useful for testcases
- *
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_drop_temporary (PGconn *db);
-
-
-/**
- * Create the necessary tables if they are not present
- *
- * @param temporary should we use a temporary schema
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_create_tables (int temporary);
-
-/**
- * Setup prepared statements. FIXME: should this be part of the API,
- * or just internal to "TALER_MINT_DB_get_connection()"?
- *
- * @param db_conn connection handle to initialize
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-int
-TALER_MINT_DB_prepare (PGconn *db_conn);
-
-
-/**
- * Start a transaction.
- *
- * @param db_conn connection to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_transaction (PGconn *db_conn);
-
-
-/**
- * Commit a transaction.
- *
- * @param db_conn connection to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_commit (PGconn *db_conn);
-
-
-/**
- * Abort/rollback a transaction.
- *
- * @param db_conn connection to use
- */
-void
-TALER_MINT_DB_rollback (PGconn *db_conn);
-
-
-/**
- * Information we keep on bank transfer(s) that established a reserve.
- */
-struct BankTransfer
-{
-
- /**
- * Public key of the reserve that was filled.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
-
- /**
- * Amount that was transferred to the mint.
- */
- struct TALER_Amount amount;
-
- /**
- * Detailed wire information about the transaction.
- */
- const json_t *wire;
-
-};
-
-
-/* FIXME: add functions to add bank transfers to our DB
- (and to test if we already did add one) (#3633/#3717) */
-
-/**
- * A summary of a Reserve
- */
-struct Reserve
-{
- /**
- * The reserve's public key. This uniquely identifies the reserve
- */
- struct GNUNET_CRYPTO_EddsaPublicKey *pub;
-
- /**
- * The balance amount existing in the reserve
- */
- struct TALER_Amount balance;
-
- /**
- * The expiration date of this reserve
- */
- struct GNUNET_TIME_Absolute expiry;
-};
-
-
-/**
- * Information we keep for a withdrawn coin to reproduce
- * the /withdraw operation if needed, and to have proof
- * that a reserve was drained by this amount.
- */
-struct CollectableBlindcoin
-{
-
- /**
- * Our signature over the (blinded) coin.
- */
- struct GNUNET_CRYPTO_rsa_Signature *sig;
-
- /**
- * Denomination key (which coin was generated).
- */
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
-
- /**
- * Public key of the reserve that was drained.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
-
- /**
- * Hash over the blinded message, needed to verify
- * the @e reserve_sig.
- */
- struct GNUNET_HashCode h_coin_envelope;
-
- /**
- * Signature confirming the withdrawl, matching @e reserve_pub,
- * @e denom_pub and @e h_coin_envelope.
- */
- struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
-};
-
-
-/**
- * Get the summary of a reserve.
- *
- * @param db the database connection handle
- * @param reserve the reserve data. The public key of the reserve should be set
- * in this structure; it is used to query the database. The balance
- * and expiration are then filled accordingly.
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_reserve_get (PGconn *db,
- struct Reserve *reserve);
-
-
-/**
- * Insert a incoming transaction into reserves. New reserves are also created
- * through this function.
- *
- * @param db the database connection handle
- * @param reserve the reserve structure. The public key of the reserve should
- * be set here. Upon successful execution of this function, the
- * balance and expiration of the reserve will be updated.
- * @param balance the amount that has to be added to the reserve
- * @param expiry the new expiration time for the reserve
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
- */
-int
-TALER_MINT_DB_reserves_in_insert (PGconn *db,
- struct Reserve *reserve,
- const struct TALER_Amount *balance,
- const struct GNUNET_TIME_Absolute expiry);
-
-
-/**
- * Locate the response for a /withdraw request under the
- * key of the hash of the blinded message.
- *
- * @param db_conn database connection to use
- * @param h_blind hash of the blinded message
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-int
-TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct CollectableBlindcoin *collectable);
-
-
-/**
- * Store collectable bit coin under the corresponding
- * hash of the blinded message.
- *
- * @param db_conn database connection to use
- * @param h_blind hash of the blinded message
- * @param withdraw amount by which the reserve will be withdrawn with this
- * transaction
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-int
-TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct TALER_Amount withdraw,
- const struct CollectableBlindcoin *collectable);
-
-
-
-/**
- * Types of operations on a reserved.
- */
-enum TALER_MINT_DB_ReserveOperation
-{
- /**
- * Money was deposited into the reserve via a bank transfer.
- */
- TALER_MINT_DB_RO_BANK_TO_MINT = 0,
-
- /**
- * A Coin was withdrawn from the reserve using /withdraw.
- */
- TALER_MINT_DB_RO_WITHDRAW_COIN = 1
-};
-
-
-/**
- * Reserve history as a linked list. Lists all of the transactions
- * associated with this reserve (such as the bank transfers that
- * established the reserve and all /withdraw operations we have done
- * since).
- */
-struct ReserveHistory
-{
-
- /**
- * Next entry in the reserve history.
- */
- struct ReserveHistory *next;
-
- /**
- * Type of the event, determins @e details.
- */
- enum TALER_MINT_DB_ReserveOperation type;
-
- /**
- * Details of the operation, depending on @e type.
- */
- union
- {
-
- /**
- * Details about a bank transfer to the mint.
- */
- struct BankTransfer *bank;
-
- /**
- * Details about a /withdraw operation.
- */
- struct CollectableBlindcoin *withdraw;
-
- } details;
-
-};
-
-
-/**
- * Get all of the transaction history associated with the specified
- * reserve.
- *
- * @param db_conn connection to use
- * @param reserve_pub public key of the reserve
- * @return known transaction history (NULL if reserve is unknown)
- */
-struct ReserveHistory *
-TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
-
-
-/**
- * Free memory associated with the given reserve history.
- *
- * @param rh history to free.
- */
-void
-TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh);
-
-
-/**
- * Specification for a /deposit operation.
- */
-struct Deposit
-{
- /**
- * Information about the coin that is being deposited.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * ECDSA signature affirming that the customer intends
- * this coin to be deposited at the merchant identified
- * by @e h_wire in relation to the contract identified
- * by @e h_contract.
- */
- struct GNUNET_CRYPTO_EcdsaSignature csig;
-
- /**
- * Public key of the merchant. Enables later identification
- * of the merchant in case of a need to rollback transactions.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
-
- /**
- * Hash over the contract between merchant and customer
- * (remains unknown to the Mint).
- */
- struct GNUNET_HashCode h_contract;
-
- /**
- * Hash of the (canonical) representation of @e wire, used
- * to check the signature on the request. Generated by
- * the mint from the detailed wire data provided by the
- * merchant.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Detailed wire information for executing the transaction.
- */
- const json_t *wire;
-
- /**
- * Merchant-generated transaction ID to detect duplicate
- * transactions.
- */
- uint64_t transaction_id;
-
- /**
- * Fraction of the coin's remaining value to be deposited.
- * The coin is identified by @e coin_pub.
- */
- struct TALER_Amount amount;
-
-};
-
-
-/**
- * Check if we have the specified deposit already in the database.
- *
- * @param db_conn database connection
- * @param deposit deposit to search for
- * @return #GNUNET_YES if we know this operation,
- * #GNUNET_NO if this deposit is unknown to us,
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_have_deposit (PGconn *db_conn,
- const struct Deposit *deposit);
-
-
-/**
- * Insert information about deposited coin into the
- * database.
- *
- * @param db_conn connection to the database
- * @param deposit deposit information to store
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_insert_deposit (PGconn *db_conn,
- const struct Deposit *deposit);
-
-
-
-/**
- * Global information for a refreshing session. Includes
- * dimensions of the operation, security parameters and
- * client signatures from "/refresh/melt" and "/refresh/commit".
- */
-struct RefreshSession
-{
- /**
- * Signature over the commitments by the client,
- * only valid if @e has_commit_sig is set.
- */
- struct GNUNET_CRYPTO_EddsaSignature commit_sig;
-
- /**
- * Hash over coins to melt and coins to create of the
- * refresh session.
- */
- struct GNUNET_HashCode session_hash;
-
- /**
- * Signature over the melt by the client.
- */
- struct GNUNET_CRYPTO_EddsaSignature melt_sig;
-
- /**
- * Number of coins we are melting.
- */
- uint16_t num_oldcoins;
-
- /**
- * Number of new coins we are creating.
- */
- uint16_t num_newcoins;
-
- /**
- * Number of parallel operations we perform for the cut and choose.
- * (must be greater or equal to three for security). 0 if not yet
- * known.
- */
- uint16_t kappa;
-
- /**
- * Index (smaller @e kappa) which the mint has chosen to not
- * have revealed during cut and choose.
- */
- uint16_t noreveal_index;
-
-};
-
-
-/**
- * Lookup refresh session data under the given public key.
- *
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use for the lookup
- * @param session[OUT] where to store the result
- * @return #GNUNET_YES on success,
- * #GNUNET_NO if not found,
- * #GNUNET_SYSERR on DB failure
- */
-int
-TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- struct RefreshSession *session);
-
-
-/**
- * Store new refresh session data under the given public key.
- *
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use to locate the session
- * @param session session data to store
- * @return #GNUNET_YES on success,
- * #GNUNET_SYSERR on DB failure
- */
-int
-TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- const struct RefreshSession *session);
-
-
-/**
- * Specification for coin in a /refresh/melt operation.
- */
-struct RefreshMelt
-{
- /**
- * Information about the coin that is being melted.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * Signature over the melting operation.
- */
- struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
-
- /**
- * Which melting operation should the coin become a part of.
- */
- struct GNUNET_HashCode melt_hash;
-
- /**
- * How much value is being melted?
- * This amount includes the fees, so the final amount contributed
- * to the melt is this value minus the fee for melting the coin.
- */
- struct TALER_Amount amount;
-
-};
-
-
-/**
- * Store the given /refresh/melt request in the database.
- *
- * @param db_conn database connection
- * @param session session key of the melt operation
- * @param oldcoin_index index of the coin to store
- * @param melt coin melt operation details to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- const struct RefreshMelt *melt);
-
-
-
-/**
- * Get information about melted coin details from the database.
- *
- * @param db_conn database connection
- * @param session session key of the melt operation
- * @param oldcoin_index index of the coin to retrieve
- * @param melt melt data to fill in
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- struct RefreshMelt *melt);
-
-
-/**
- * Store in the database which coin(s) we want to create
- * in a given refresh operation.
- *
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub);
-
-
-/**
- * Lookup in the database the @a newcoin_index coin that we want to
- * create in the given refresh operation.
- *
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
- * @return NULL on error (not found or internal error)
- */
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index);
-
-
-/**
- * We have as many `struct RefreshCommitCoin` as there are new
- * coins being created by the refresh (for each of the kappa
- * sets). These are the coins we ask the mint to sign if the
- * respective set is selected.
- */
-struct RefreshCommitCoin
-{
-
- /**
- * Encrypted data allowing those able to decrypt it to derive
- * the private keys of the new coins created by the refresh.
- */
- struct TALER_RefreshLinkEncrypted *refresh_link;
-
- /**
- * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
- */
- char *coin_ev;
-
- /**
- * Number of bytes in @e coin_ev.
- */
- size_t coin_ev_size;
-
-};
-
-
-/**
- * Store information about the commitment of the
- * given coin for the given refresh session in the database.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session this commitment belongs to
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
- * @param commit_coin coin commitment to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitCoin *commit_coin);
-
-
-/**
- * Obtain information about the commitment of the
- * given coin of the given refresh session from the database.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session the commitment belongs to
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
- * @param commit_coin[OUT] coin commitment to return
- * @return #GNUNET_OK on success
- * #GNUNET_NO if not found
- * #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- struct RefreshCommitCoin *commit_coin);
-
-
-/**
- * For each (old) coin being melted, we have a `struct
- * RefreshCommitLink` that allows the user to find the shared secret
- * to decrypt the respective refresh links for the new coins in the
- * `struct RefreshCommitCoin`.
- */
-struct RefreshCommitLink
-{
- /**
- * Transfer public key (FIXME: explain!)
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
-
- /**
- * Encrypted shared secret to decrypt the link.
- */
- struct TALER_EncryptedLinkSecret shared_secret_enc;
-};
-
-
-/**
- * Store the commitment to the given (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to melted (old) coins
- * @param commit_link link information to store
- * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitLink *commit_link);
-
-/**
- * Obtain the commited (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to melted (old) coins
- * @param cc[OUT] link information to return
- * @return #GNUNET_SYSERR on internal error,
- * #GNUNET_NO if commitment was not found
- * #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- struct RefreshCommitLink *cc);
-
-
-/**
- * Insert signature of a new coin generated during refresh into
- * the database indexed by the refresh session and the index
- * of the coin. This data is later used should an old coin
- * be used to try to obtain the private keys during "/refresh/link".
- *
- * @param db_conn database connection
- * @param session_pub refresh session
- * @param newcoin_index coin index
- * @param ev_sig coin signature
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_Signature *ev_sig);
-
-
-/**
- * Linked list of refresh information linked to a coin.
- */
-struct LinkDataList
-{
- /**
- * Information is stored in a NULL-terminated linked list.
- */
- struct LinkDataList *next;
-
- /**
- * Link data, used to recover the private key of the coin
- * by the owner of the old coin.
- */
- struct TALER_RefreshLinkEncrypted *link_data_enc;
-
- /**
- * Denomination public key, determines the value of the coin.
- */
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
-
- /**
- * Signature over the blinded envelope.
- */
- struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
-};
-
-
-/**
- * Obtain the link data of a coin, that is the encrypted link
- * information, the denomination keys and the signatures.
- *
- * @param db_conn database connection
- * @param coin_pub public key to use to retrieve linkage data
- * @return all known link data for the coin
- */
-struct LinkDataList *
-TALER_db_get_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
-
-
-/**
- * Free memory of the link data list.
- *
- * @param ldl link data list to release
- */
-void
-TALER_db_link_data_list_free (struct LinkDataList *ldl);
-
-
-/**
- * Obtain shared secret and transfer public key from the public key of
- * the coin. This information and the link information returned by
- * #TALER_db_get_link() enable the owner of an old coin to determine
- * the private keys of the new coins after the melt.
- *
- *
- * @param db_conn database connection
- * @param coin_pub public key of the coin
- * @param transfer_pub[OUT] public transfer key
- * @param shared_secret_enc[OUT] set to shared secret
- * @return #GNUNET_OK on success,
- * #GNUNET_NO on failure (not found)
- * #GNUNET_SYSERR on internal failure (database issue)
- */
-int
-TALER_db_get_transfer (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
- struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
- struct TALER_EncryptedLinkSecret *shared_secret_enc);
-
-
-/**
- * Specification for a /lock operation.
- */
-struct Lock
-{
- /**
- * Information about the coin that is being melted.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * Signature over the melting operation.
- */
- const struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
-
- /**
- * How much value is being melted?
- */
- struct TALER_Amount amount;
-
- // FIXME: more needed...
-};
-
-
-/**
- * Test if the given /lock request is known to us.
- *
- * @param db_conn database connection
- * @param lock lock operation
- * @return #GNUNET_YES if known,
- * #GNUENT_NO if not,
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_have_lock (PGconn *db_conn,
- const struct Lock *lock);
-
-
-/**
- * Store the given /lock request in the database.
- *
- * @param db_conn database connection
- * @param lock lock operation
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_lock (PGconn *db_conn,
- const struct Lock *lock);
-
-
-/**
- * Enumeration to classify the different types of transactions
- * that can be done with a coin.
- */
-enum TALER_MINT_DB_TransactionType
-{
- /**
- * /deposit operation.
- */
- TALER_MINT_DB_TT_DEPOSIT = 0,
-
- /**
- * /refresh/melt operation.
- */
- TALER_MINT_DB_TT_REFRESH_MELT = 1,
-
- /**
- * /lock operation.
- */
- TALER_MINT_DB_TT_LOCK = 2
-};
-
-
-/**
- * List of transactions we performed for a particular coin.
- */
-struct TALER_MINT_DB_TransactionList
-{
-
- /**
- * Next pointer in the NULL-terminated linked list.
- */
- struct TALER_MINT_DB_TransactionList *next;
-
- /**
- * Type of the transaction, determines what is stored in @e details.
- */
- enum TALER_MINT_DB_TransactionType type;
-
- /**
- * Details about the transaction, depending on @e type.
- */
- union
- {
-
- /**
- * Details if transaction was a /deposit operation.
- */
- struct Deposit *deposit;
-
- /**
- * Details if transaction was a /refresh/melt operation.
- */
- struct RefreshMelt *melt;
-
- /**
- * Details if transaction was a /lock operation.
- */
- struct Lock *lock;
-
- } details;
-
-};
-
-
-/**
- * Compile a list of all (historic) transactions performed
- * with the given coin (/refresh/melt and /deposit operations).
- *
- * @param db_conn database connection
- * @param coin_pub coin to investigate
- * @return list of transactions, NULL if coin is fresh
- */
-struct TALER_MINT_DB_TransactionList *
-TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
-
-
-/**
- * Free linked list of transactions.
- *
- * @param list list to free
- */
-void
-TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list);
-
-
-
-#endif /* _NEURO_MINT_DB_H */
diff --git a/src/mint/plugin.c b/src/mint/plugin.c
new file mode 100644
index 000000000..91cd3f406
--- /dev/null
+++ b/src/mint/plugin.c
@@ -0,0 +1,183 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+
+ 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, If not, see
+*/
+/**
+ * @file mint/plugin.c
+ * @brief Logic to load database plugin
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "plugin.h"
+#include
+
+
+/**
+ * Global variable with the plugin (once loaded).
+ */
+struct TALER_MINTDB_Plugin *plugin;
+
+/**
+ * Libtool search path before we started.
+ */
+static char *old_dlsearchpath;
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_MINT_plugin_load (struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Shutdown the plugin.
+ */
+void
+TALER_MINT_plugin_unload ()
+{
+ if (NULL == plugin)
+ return;
+}
+
+
+/**
+ * Setup libtool paths.
+ */
+void __attribute__ ((constructor))
+plugin_init ()
+{
+ int err;
+ const char *opath;
+ char *path;
+ char *cpath;
+
+ err = lt_dlinit ();
+ if (err > 0)
+ {
+ FPRINTF (stderr,
+ _("Initialization of plugin mechanism failed: %s!\n"),
+ lt_dlerror ());
+ return;
+ }
+ opath = lt_dlgetsearchpath ();
+ if (NULL != opath)
+ old_dlsearchpath = GNUNET_strdup (opath);
+ path = TALER_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
+ if (NULL != path)
+ {
+ if (NULL != opath)
+ {
+ GNUNET_asprintf (&cpath, "%s:%s", opath, path);
+ lt_dlsetsearchpath (cpath);
+ GNUNET_free (path);
+ GNUNET_free (cpath);
+ }
+ else
+ {
+ lt_dlsetsearchpath (path);
+ GNUNET_free (path);
+ }
+ }
+}
+
+
+/**
+ * Shutdown libtool.
+ */
+void __attribute__ ((destructor))
+plugin_fini ()
+{
+ lt_dlsetsearchpath (old_dlsearchpath);
+ if (NULL != old_dlsearchpath)
+ {
+ GNUNET_free (old_dlsearchpath);
+ old_dlsearchpath = NULL;
+ }
+ lt_dlexit ();
+}
+
+
+// FIXME: decide if we should keep these in each plugin, here
+// or yet again somewhere else entirely (plugin_common.c?)
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param rh history to free.
+ */
+void
+TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh)
+{
+ struct BankTransfer *bt;
+ struct CollectableBlindcoin *cbc;
+ struct ReserveHistory *backref;
+
+ while (NULL != rh)
+ {
+ switch(rh->type)
+ {
+ case TALER_MINT_DB_RO_BANK_TO_MINT:
+ bt = rh->details.bank;
+ if (NULL != bt->wire)
+ json_decref ((json_t *) bt->wire); /* FIXME: avoid cast? */
+ GNUNET_free (bt);
+ break;
+ case TALER_MINT_DB_RO_WITHDRAW_COIN:
+ cbc = rh->details.withdraw;
+ GNUNET_CRYPTO_rsa_signature_free (cbc->sig);
+ GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub);
+ GNUNET_free (cbc);
+ break;
+ }
+ backref = rh;
+ rh = rh->next;
+ GNUNET_free (backref);
+ }
+}
+
+
+/**
+ * Free memory of the link data list.
+ *
+ * @param ldl link data list to release
+ */
+void
+TALER_db_link_data_list_free (struct LinkDataList *ldl)
+{
+ GNUNET_break (0); // FIXME
+}
+
+
+/**
+ * Free linked list of transactions.
+ *
+ * @param list list to free
+ */
+void
+TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list)
+{
+ // FIXME: check logic!
+ GNUNET_break (0);
+}
+
+
+
+/* end of plugin.c */
diff --git a/src/mint/plugin.h b/src/mint/plugin.h
new file mode 100644
index 000000000..01b99ebc3
--- /dev/null
+++ b/src/mint/plugin.h
@@ -0,0 +1,77 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015 Christian Grothoff (and other contributing authors)
+
+ 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, If not, see
+*/
+/**
+ * @file mint/plugin.h
+ * @brief Logic to load database plugins
+ * @author Christian Grothoff
+ */
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include
+#include "taler_mintdb_plugin.h"
+
+/**
+ * Global variable with the plugin (once loaded).
+ */
+extern struct TALER_MINTDB_Plugin *plugin;
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_MINT_plugin_load (struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Shutdown the plugin.
+ */
+void
+TALER_MINT_plugin_unload (void);
+
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param rh history to free.
+ */
+void
+TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh);
+
+
+/**
+ * Free memory of the link data list.
+ *
+ * @param ldl link data list to release
+ */
+void
+TALER_db_link_data_list_free (struct LinkDataList *ldl);
+
+
+/**
+ * Free linked list of transactions.
+ *
+ * @param list list to free
+ */
+void
+TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list);
+
+
+#endif
diff --git a/src/mint/mint_db.c b/src/mint/plugin_mintdb_postgres.c
similarity index 78%
rename from src/mint/mint_db.c
rename to src/mint/plugin_mintdb_postgres.c
index 6832cdac9..8935fe039 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/plugin_mintdb_postgres.c
@@ -15,41 +15,25 @@
*/
/**
- * @file mint_db.c
- * @brief Low-level (statement-level) database access for the mint
+ * @file plugin_mintdb_postgres.c
+ * @brief Low-level (statement-level) Postgres database access for the mint
* @author Florian Dold
* @author Christian Grothoff
* @author Sree Harsha Totakura
- *
- * TODO:
- * - The mint_db.h-API should ideally be what we need to port
- * when using other databases; so here we should enable
- * alternative implementations by returning
- * a more opaque DB handle.
*/
#include "platform.h"
#include "db_pq.h"
#include "taler_signatures.h"
-#include "taler-mint-httpd_responses.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include
+#include
-/**
- * Thread-local database connection.
- * Contains a pointer to PGconn or NULL.
- */
-static pthread_key_t db_conn_threadlocal;
-
+#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
#define QUERY_ERR(result) \
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result))
-/**
- * Database connection string, as read from
- * the configuration.
- */
-static char *TALER_MINT_db_connection_cfg_str;
#define BREAK_DB_ERR(result) do { \
GNUNET_break(0); \
@@ -84,6 +68,41 @@ static char *TALER_MINT_db_connection_cfg_str;
*/
#define TALER_DB_CURRENCY_LEN 3
+
+/**
+ * Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_MINTDB_Session
+{
+ /**
+ * Postgres connection handle.
+ */
+ PGconn *conn;
+};
+
+
+/**
+ * Type of the "cls" argument given to each of the functions in
+ * our API.
+ */
+struct PostgresClosure
+{
+
+ /**
+ * Thread-local database connection.
+ * Contains a pointer to PGconn or NULL.
+ */
+ pthread_key_t db_conn_threadlocal;
+
+ /**
+ * Database connection string, as read from
+ * the configuration.
+ */
+ char *TALER_MINT_db_connection_cfg_str;
+};
+
+
+
/**
* Set the given connection to use a temporary schema
*
@@ -108,14 +127,16 @@ set_temporary_schema (PGconn *db)
/**
* Drop the temporary taler schema. This is only useful for testcases
*
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_drop_temporary (PGconn *db)
+static int
+postgres_drop_temporary (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- SQLEXEC_ (db,
+ SQLEXEC_ (session->conn,
"DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;",
result);
return GNUNET_OK;
@@ -127,17 +148,19 @@ TALER_MINT_DB_drop_temporary (PGconn *db)
/**
* Create the necessary tables if they are not present
*
+ * @param pc our overall context
* @param temporary should we use a temporary schema
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_create_tables (int temporary)
+static int
+postgres_create_tables (struct PostgresClosure *pc,
+ int temporary)
{
PGresult *result;
PGconn *conn;
result = NULL;
- conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
+ conn = PQconnectdb (pc->TALER_MINT_db_connection_cfg_str);
if (CONNECTION_OK != PQstatus (conn))
{
LOG_ERROR ("Database connection failed: %s\n",
@@ -279,8 +302,8 @@ TALER_MINT_DB_create_tables (int temporary)
* @param db_conn connection handle to initialize
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
-int
-TALER_MINT_DB_prepare (PGconn *db_conn)
+static int
+postgres_prepare (PGconn *db_conn)
{
PGresult *result;
@@ -581,42 +604,26 @@ db_conn_destroy (void *cls)
}
-/**
- * Initialize database subsystem.
- *
- * @param connection_cfg configuration to use to talk to DB
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_init (const char *connection_cfg)
-{
- if (0 != pthread_key_create (&db_conn_threadlocal,
- &db_conn_destroy))
- {
- LOG_ERROR ("Cannnot create pthread key.\n");
- return GNUNET_SYSERR;
- }
- TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg);
- return GNUNET_OK;
-}
-
-
/**
* Get the thread-local database-handle.
* Connect to the db if the connection does not exist yet.
*
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
* @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
* database default one
* @return the database connection, or NULL on error
*/
-PGconn *
-TALER_MINT_DB_get_connection (int temporary)
+static struct TALER_MINTDB_Session *
+postgres_get_connection (void *cls,
+ int temporary)
{
+ struct PostgresClosure *pc = cls;
PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
- if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal)))
- return db_conn;
- db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
+ if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal)))
+ return session;
+ db_conn = PQconnectdb (pc->TALER_MINT_db_connection_cfg_str);
if (CONNECTION_OK !=
PQstatus (db_conn))
{
@@ -632,33 +639,39 @@ TALER_MINT_DB_get_connection (int temporary)
return NULL;
}
if (GNUNET_OK !=
- TALER_MINT_DB_prepare (db_conn))
+ postgres_prepare (db_conn))
{
GNUNET_break (0);
return NULL;
}
- if (0 != pthread_setspecific (db_conn_threadlocal,
- db_conn))
+ session = GNUNET_new (struct TALER_MINTDB_Session);
+ session->conn = db_conn;
+ if (0 != pthread_setspecific (pc->db_conn_threadlocal,
+ session))
{
GNUNET_break (0);
+ // FIXME: close db_conn!
+ GNUNET_free (session);
return NULL;
}
- return db_conn;
+ return session;
}
/**
* Start a transaction.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_transaction (PGconn *db_conn)
+static int
+postgres_start (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"BEGIN");
if (PGRES_COMMAND_OK !=
PQresultStatus (result))
@@ -678,15 +691,17 @@ TALER_MINT_DB_transaction (PGconn *db_conn)
/**
* Roll back the current transaction of a database connection.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-void
-TALER_MINT_DB_rollback (PGconn *db_conn)
+static void
+postgres_rollback (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"ROLLBACK");
GNUNET_break (PGRES_COMMAND_OK ==
PQresultStatus (result));
@@ -697,15 +712,17 @@ TALER_MINT_DB_rollback (PGconn *db_conn)
/**
* Commit the current transaction of a database connection.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_commit (PGconn *db_conn)
+static int
+postgres_commit (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"COMMIT");
if (PGRES_COMMAND_OK !=
PQresultStatus (result))
@@ -723,15 +740,17 @@ TALER_MINT_DB_commit (PGconn *db_conn)
/**
* Get the summary of a reserve.
*
- * @param db the database connection handle
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
* @param reserve the reserve data. The public key of the reserve should be set
* in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_reserve_get (PGconn *db,
- struct Reserve *reserve)
+static int
+postgres_reserve_get (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve)
{
PGresult *result;
uint64_t expiration_date_nbo;
@@ -745,7 +764,7 @@ TALER_MINT_DB_reserve_get (PGconn *db,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserve",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -783,14 +802,16 @@ TALER_MINT_DB_reserve_get (PGconn *db,
/**
* Updates a reserve with the data from the given reserve structure.
*
- * @param db the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @param reserve the reserve structure whose data will be used to update the
* corresponding record in the database.
* @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error
*/
-int
-reserves_update (PGconn *db,
- struct Reserve *reserve)
+static int
+postgres_reserves_update (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve)
{
PGresult *result;
struct TALER_AmountNBO balance_nbo;
@@ -810,7 +831,7 @@ reserves_update (PGconn *db,
TALER_amount_hton (&balance_nbo,
&reserve->balance);
expiry_nbo = GNUNET_TIME_absolute_hton (reserve->expiry);
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"update_reserve",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -827,7 +848,8 @@ reserves_update (PGconn *db,
* Insert a incoming transaction into reserves. New reserves are also created
* through this function.
*
- * @param db the database connection handle
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
* @param reserve the reserve structure. The public key of the reserve should
* be set here. Upon successful execution of this function, the
* balance and expiration of the reserve will be updated.
@@ -835,11 +857,12 @@ reserves_update (PGconn *db,
* @param expiry the new expiration time for the reserve
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
*/
-int
-TALER_MINT_DB_reserves_in_insert (PGconn *db,
- struct Reserve *reserve,
- const struct TALER_Amount *balance,
- const struct GNUNET_TIME_Absolute expiry)
+static int
+postgres_reserves_in_insert (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve,
+ const struct TALER_Amount *balance,
+ const struct GNUNET_TIME_Absolute expiry)
{
struct TALER_AmountNBO balance_nbo;
struct GNUNET_TIME_AbsoluteNBO expiry_nbo;
@@ -852,15 +875,19 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (GNUNET_OK != TALER_MINT_DB_transaction (db))
+ if (GNUNET_OK != postgres_start (cls,
+ session))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- reserve_exists = TALER_MINT_DB_reserve_get (db, reserve);
+ reserve_exists = postgres_reserve_get (cls,
+ session,
+ reserve);
if (GNUNET_SYSERR == reserve_exists)
{
- TALER_MINT_DB_rollback (db);
+ postgres_rollback (cls,
+ session);
return GNUNET_SYSERR;
}
TALER_amount_hton (&balance_nbo,
@@ -879,7 +906,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"create_reserve",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -901,7 +928,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"create_reserves_in_transaction",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -913,7 +940,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
result = NULL;
if (GNUNET_NO == reserve_exists)
{
- if (GNUNET_OK != TALER_MINT_DB_commit (db))
+ if (GNUNET_OK != postgres_commit (cls,
+ session))
return GNUNET_SYSERR;
reserve->balance = *balance;
reserve->expiry = expiry;
@@ -931,9 +959,12 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
return GNUNET_SYSERR;
}
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve->expiry);
- if (GNUNET_OK != reserves_update (db, &updated_reserve))
+ if (GNUNET_OK != postgres_reserves_update (cls,
+ session,
+ &updated_reserve))
goto rollback;
- if (GNUNET_OK != TALER_MINT_DB_commit (db))
+ if (GNUNET_OK != postgres_commit (cls,
+ session))
return GNUNET_SYSERR;
reserve->balance = updated_reserve.balance;
reserve->expiry = updated_reserve.expiry;
@@ -941,7 +972,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
rollback:
PQclear (result);
- TALER_MINT_DB_rollback (db);
+ postgres_rollback (cls,
+ session);
return GNUNET_SYSERR;
}
@@ -950,7 +982,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
* Locate the response for a /withdraw request under the
* key of the hash of the blinded message.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param h_blind hash of the blinded message
* @param collectable corresponding collectable coin (blind signature)
* if a coin is found
@@ -958,10 +991,11 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
* #GNUNET_NO if the collectable was not found
* #GNUNET_YES on success
*/
-int
-TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct CollectableBlindcoin *collectable)
+static int
+postgres_get_collectable_blindcoin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct CollectableBlindcoin *collectable)
{
PGresult *result;
struct TALER_DB_QueryParam params[] = {
@@ -980,7 +1014,7 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
denom_pub = NULL;
denom_pub_enc = NULL;
denom_sig_enc = NULL;
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_collectable_blindcoin",
params);
@@ -1038,7 +1072,8 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
* Store collectable bit coin under the corresponding
* hash of the blinded message.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param h_blind hash of the blinded message
* @param withdraw amount by which the reserve will be withdrawn with this
* transaction
@@ -1048,11 +1083,12 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
* #GNUNET_NO if the collectable was not found
* #GNUNET_YES on success
*/
-int
-TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct TALER_Amount withdraw,
- const struct CollectableBlindcoin *collectable)
+static int
+postgres_insert_collectable_blindcoin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_Amount withdraw,
+ const struct CollectableBlindcoin *collectable)
{
PGresult *result;
struct Reserve reserve;
@@ -1077,9 +1113,10 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig),
TALER_DB_QUERY_PARAM_END
};
- if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
+ if (GNUNET_OK != postgres_start (cls,
+ session))
goto cleanup;
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"insert_collectable_blindcoin",
params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -1089,24 +1126,29 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
}
reserve.pub = (struct GNUNET_CRYPTO_EddsaPublicKey *)
&collectable->reserve_pub;
- if (GNUNET_OK != TALER_MINT_DB_reserve_get (db_conn,
- &reserve))
+ if (GNUNET_OK != postgres_reserve_get (cls,
+ session,
+ &reserve))
goto rollback;
if (GNUNET_SYSERR ==
TALER_amount_subtract (&reserve.balance,
&reserve.balance,
&withdraw))
goto rollback;
- if (GNUNET_OK != reserves_update (db_conn, &reserve))
+ if (GNUNET_OK != postgres_reserves_update (cls,
+ session,
+ &reserve))
goto rollback;
- if (GNUNET_OK == TALER_MINT_DB_commit (db_conn))
+ if (GNUNET_OK == postgres_commit (cls,
+ session))
{
ret = GNUNET_OK;
goto cleanup;
}
rollback:
- TALER_MINT_DB_rollback(db_conn);
+ postgres_rollback (cls,
+ session);
cleanup:
PQclear (result);
GNUNET_free_non_null (denom_pub_enc);
@@ -1119,13 +1161,15 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
* Get all of the transaction history associated with the specified
* reserve.
*
- * @param db_conn connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to use
* @param reserve_pub public key of the reserve
* @return known transaction history (NULL if reserve is unknown)
*/
-struct ReserveHistory *
-TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
+static struct ReserveHistory *
+postgres_get_reserve_history (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
{
PGresult *result;
struct ReserveHistory *rh;
@@ -1144,7 +1188,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserves_in_transactions",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1202,7 +1246,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR (reserve_pub),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserves_blindcoins",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1274,53 +1318,19 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
}
-/**
- * Free memory associated with the given reserve history.
- *
- * @param rh history to free.
- */
-void
-TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh)
-{
- struct BankTransfer *bt;
- struct CollectableBlindcoin *cbc;
- struct ReserveHistory *backref;
-
- while (NULL != rh)
- {
- switch(rh->type)
- {
- case TALER_MINT_DB_RO_BANK_TO_MINT:
- bt = rh->details.bank;
- if (NULL != bt->wire)
- json_decref ((json_t *) bt->wire); /* FIXME: avoid cast? */
- GNUNET_free (bt);
- break;
- case TALER_MINT_DB_RO_WITHDRAW_COIN:
- cbc = rh->details.withdraw;
- GNUNET_CRYPTO_rsa_signature_free (cbc->sig);
- GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub);
- GNUNET_free (cbc);
- break;
- }
- backref = rh;
- rh = rh->next;
- GNUNET_free (backref);
- }
-}
-
-
/**
* Check if we have the specified deposit already in the database.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param deposit deposit to search for
* @return #GNUNET_YES if we know this operation,
* #GNUNET_NO if this deposit is unknown to us
*/
-int
-TALER_MINT_DB_have_deposit (PGconn *db_conn,
- const struct Deposit *deposit)
+static int
+postgres_have_deposit (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct Deposit *deposit)
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
@@ -1332,7 +1342,7 @@ TALER_MINT_DB_have_deposit (PGconn *db_conn,
int ret;
ret = GNUNET_SYSERR;
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_deposit",
params);
if (PGRES_TUPLES_OK !=
@@ -1359,13 +1369,15 @@ TALER_MINT_DB_have_deposit (PGconn *db_conn,
* Insert information about deposited coin into the
* database.
*
- * @param db_conn connection to the database
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to the database
* @param deposit deposit information to store
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_insert_deposit (PGconn *db_conn,
- const struct Deposit *deposit)
+static int
+postgres_insert_deposit (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct Deposit *deposit)
{
char *denom_pub_enc;
char *denom_sig_enc;
@@ -1403,7 +1415,7 @@ TALER_MINT_DB_insert_deposit (PGconn *db_conn,
strlen (json_wire_enc)),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params);
+ result = TALER_DB_exec_prepared (session->conn, "insert_deposit", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
BREAK_DB_ERR (result);
@@ -1423,17 +1435,19 @@ TALER_MINT_DB_insert_deposit (PGconn *db_conn,
/**
* Lookup refresh session data under the given public key.
*
- * @param db_conn database handle to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
* @param refresh_session_pub public key to use for the lookup
- * @param session[OUT] where to store the result
+ * @param refresh_session[OUT] where to store the result
* @return #GNUNET_YES on success,
* #GNUNET_NO if not found,
* #GNUNET_SYSERR on DB failure
*/
-int
-TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- struct RefreshSession *session)
+static int
+postgres_get_refresh_session (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ struct RefreshSession *refresh_session)
{
// FIXME: check logic!
int res;
@@ -1442,7 +1456,9 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_session", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "get_refresh_session",
+ params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1461,16 +1477,16 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
/* We're done if the caller is only interested in
* whether the session exists or not */
- if (NULL == session)
+ if (NULL == refresh_session)
return GNUNET_YES;
memset (session, 0, sizeof (struct RefreshSession));
struct TALER_DB_ResultSpec rs[] = {
- TALER_DB_RESULT_SPEC("num_oldcoins", &session->num_oldcoins),
- TALER_DB_RESULT_SPEC("num_newcoins", &session->num_newcoins),
- TALER_DB_RESULT_SPEC("kappa", &session->kappa),
- TALER_DB_RESULT_SPEC("noreveal_index", &session->noreveal_index),
+ TALER_DB_RESULT_SPEC("num_oldcoins", &refresh_session->num_oldcoins),
+ TALER_DB_RESULT_SPEC("num_newcoins", &refresh_session->num_newcoins),
+ TALER_DB_RESULT_SPEC("kappa", &refresh_session->kappa),
+ TALER_DB_RESULT_SPEC("noreveal_index", &refresh_session->noreveal_index),
TALER_DB_RESULT_SPEC_END
};
@@ -1483,10 +1499,10 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
return GNUNET_SYSERR;
}
- session->num_oldcoins = ntohs (session->num_oldcoins);
- session->num_newcoins = ntohs (session->num_newcoins);
- session->kappa = ntohs (session->kappa);
- session->noreveal_index = ntohs (session->noreveal_index);
+ refresh_session->num_oldcoins = ntohs (refresh_session->num_oldcoins);
+ refresh_session->num_newcoins = ntohs (refresh_session->num_newcoins);
+ refresh_session->kappa = ntohs (refresh_session->kappa);
+ refresh_session->noreveal_index = ntohs (refresh_session->noreveal_index);
PQclear (result);
return GNUNET_YES;
@@ -1496,16 +1512,18 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
/**
* Store new refresh session data under the given public key.
*
- * @param db_conn database handle to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
* @param refresh_session_pub public key to use to locate the session
- * @param session session data to store
+ * @param refresh_session session data to store
* @return #GNUNET_YES on success,
* #GNUNET_SYSERR on DB failure
*/
-int
-TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- const struct RefreshSession *session)
+static int
+postgres_create_refresh_session (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ const struct RefreshSession *refresh_session)
{
// FIXME: actually store session data!
uint16_t noreveal_index;
@@ -1518,7 +1536,9 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
noreveal_index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1<<15);
noreveal_index = htonl (noreveal_index);
- PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_session", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "insert_refresh_session",
+ params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
@@ -1535,18 +1555,20 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
/**
* Store the given /refresh/melt request in the database.
*
- * @param db_conn database connection
- * @param session session key of the melt operation
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param refresh_session session key of the melt operation
* @param oldcoin_index index of the coin to store
* @param melt melt operation
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- const struct RefreshMelt *melt)
+static int
+postgres_insert_refresh_melt (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ uint16_t oldcoin_index,
+ const struct RefreshMelt *melt)
{
// FIXME: check logic!
uint16_t oldcoin_index_nbo = htons (oldcoin_index);
@@ -1558,13 +1580,15 @@ TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
&buf);
{
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(session),
+ TALER_DB_QUERY_PARAM_PTR(refresh_session),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&melt->coin.coin_pub),
TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params);
+ result = TALER_DB_exec_prepared (session->conn,
+ "insert_refresh_melt",
+ params);
}
GNUNET_free (buf);
if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -1581,18 +1605,20 @@ TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
/**
* Get information about melted coin details from the database.
*
- * @param db_conn database connection
- * @param session session key of the melt operation
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param refresh_session session key of the melt operation
* @param oldcoin_index index of the coin to retrieve
* @param melt melt data to fill in
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- struct RefreshMelt *melt)
+static int
+postgres_get_refresh_melt (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ uint16_t oldcoin_index,
+ struct RefreshMelt *melt)
{
// FIXME: check logic!
GNUNET_break (0);
@@ -1604,18 +1630,20 @@ TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
* Store in the database which coin(s) we want to create
* in a given refresh operation.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param session_pub refresh session key
* @param newcoin_index index of the coin to generate
* @param denom_pub denomination of the coin to create
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
+static int
+postgres_insert_refresh_order (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index,
+ const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
{
// FIXME: check logic
uint16_t newcoin_index_nbo = htons (newcoin_index);
@@ -1633,7 +1661,7 @@ TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR_SIZED (buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_order",
params);
}
@@ -1658,16 +1686,18 @@ TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
* Lookup in the database the @a newcoin_index coin that we want to
* create in the given refresh operation.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param session_pub refresh session key
* @param newcoin_index index of the coin to generate
* @param denom_pub denomination of the coin to create
* @return NULL on error (not found or internal error)
*/
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index)
+static struct GNUNET_CRYPTO_rsa_PublicKey *
+postgres_get_refresh_order (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index)
{
// FIXME: check logic
char *buf;
@@ -1681,7 +1711,7 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_order", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_refresh_order", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1719,7 +1749,8 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
* Store information about the commitment of the
* given coin for the given refresh session in the database.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param refresh_session_pub refresh session this commitment belongs to
* @param i set index (1st dimension)
* @param j coin index (2nd dimension), corresponds to refreshed (new) coins
@@ -1727,12 +1758,13 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitCoin *commit_coin)
+static int
+postgres_insert_refresh_commit_coin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ const struct RefreshCommitCoin *commit_coin)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (i);
@@ -1748,7 +1780,7 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_commit_coin", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "insert_refresh_commit_coin", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
@@ -1772,7 +1804,8 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
* Obtain information about the commitment of the
* given coin of the given refresh session from the database.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param refresh_session_pub refresh session the commitment belongs to
* @param i set index (1st dimension)
* @param j coin index (2nd dimension), corresponds to refreshed (new) coins
@@ -1781,12 +1814,13 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
* #GNUNET_NO if not found
* #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int cnc_index,
- unsigned int newcoin_index,
- struct RefreshCommitCoin *cc)
+static int
+postgres_get_refresh_commit_coin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int cnc_index,
+ unsigned int newcoin_index,
+ struct RefreshCommitCoin *cc)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (cnc_index);
@@ -1803,7 +1837,7 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
size_t rl_buf_size;
struct TALER_RefreshLinkEncrypted *rl;
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_commit_coin", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_refresh_commit_coin", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1849,7 +1883,8 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
* Store the commitment to the given (encrypted) refresh link data
* for the given refresh session.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param refresh_session_pub public key of the refresh session this
* commitment belongs with
* @param i set index (1st dimension)
@@ -1857,12 +1892,13 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
* @param commit_link link information to store
* @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitLink *commit_link)
+static int
+postgres_insert_refresh_commit_link (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ const struct RefreshCommitLink *commit_link)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (i);
@@ -1876,7 +1912,7 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn,
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_commit_link",
params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -1901,7 +1937,8 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
* Obtain the commited (encrypted) refresh link data
* for the given refresh session.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param refresh_session_pub public key of the refresh session this
* commitment belongs with
* @param i set index (1st dimension)
@@ -1911,12 +1948,13 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
* #GNUNET_NO if commitment was not found
* #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int cnc_index,
- unsigned int oldcoin_index,
- struct RefreshCommitLink *cc)
+static int
+postgres_get_refresh_commit_link (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int cnc_index,
+ unsigned int oldcoin_index,
+ struct RefreshCommitLink *cc)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (cnc_index);
@@ -1929,7 +1967,7 @@ TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn,
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
"get_refresh_commit_link",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1969,17 +2007,19 @@ TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
* of the coin. This data is later used should an old coin
* be used to try to obtain the private keys during "/refresh/link".
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param session_pub refresh session
* @param newcoin_index coin index
* @param ev_sig coin signature
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_Signature *ev_sig)
+static int
+postgres_insert_refresh_collectable (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index,
+ const struct GNUNET_CRYPTO_rsa_Signature *ev_sig)
{
// FIXME: check logic!
uint16_t newcoin_index_nbo = htons (newcoin_index);
@@ -1996,7 +2036,7 @@ TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_collectable",
params);
}
@@ -2016,12 +2056,14 @@ TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
* Obtain the link data of a coin, that is the encrypted link
* information, the denomination keys and the signatures.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub public key to use to retrieve linkage data
* @return all known link data for the coin
*/
-struct LinkDataList *
-TALER_db_get_link (PGconn *db_conn,
+static struct LinkDataList *
+postgres_get_link (void *cls,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
{
// FIXME: check logic!
@@ -2031,7 +2073,7 @@ TALER_db_get_link (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR(coin_pub),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_link", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_link", params);
ldl = NULL;
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -2124,26 +2166,14 @@ TALER_db_get_link (PGconn *db_conn,
}
-/**
- * Free memory of the link data list.
- *
- * @param ldl link data list to release
- */
-void
-TALER_db_link_data_list_free (struct LinkDataList *ldl)
-{
- GNUNET_break (0); // FIXME
-}
-
-
/**
* Obtain shared secret and transfer public key from the public key of
* the coin. This information and the link information returned by
* #TALER_db_get_link() enable the owner of an old coin to determine
* the private keys of the new coins after the melt.
*
- *
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub public key of the coin
* @param transfer_pub[OUT] public transfer key
* @param shared_secret_enc[OUT] set to shared secret
@@ -2151,8 +2181,9 @@ TALER_db_link_data_list_free (struct LinkDataList *ldl)
* #GNUNET_NO on failure (not found)
* #GNUNET_SYSERR on internal failure (database issue)
*/
-int
-TALER_db_get_transfer (PGconn *db_conn,
+static int
+postgres_get_transfer (void *cls,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
struct TALER_EncryptedLinkSecret *shared_secret_enc)
@@ -2163,7 +2194,7 @@ TALER_db_get_transfer (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_transfer", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_transfer", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -2205,19 +2236,19 @@ TALER_db_get_transfer (PGconn *db_conn,
}
-
-
/**
* Compile a list of all (historic) transactions performed
* with the given coin (/refresh/melt and /deposit operations).
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub coin to investigate
* @return list of transactions, NULL if coin is fresh
*/
-struct TALER_MINT_DB_TransactionList *
-TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
+static struct TALER_MINT_DB_TransactionList *
+postgres_get_coin_transactions (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
{
// FIXME: check logic!
GNUNET_break (0); // FIXME: implement!
@@ -2225,17 +2256,61 @@ TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
}
+
/**
- * Free linked list of transactions.
+ * Initialize Postgres database subsystem.
*
- * @param list list to free
+ * @param cls a configuration instance
+ * @return NULL on error, otherwise a `struct TALER_MINTDB_Plugin`
*/
-void
-TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list)
+void *
+libtaler_plugin_mintdb_postgres_init (void *cls)
{
- // FIXME: check logic!
- GNUNET_break (0);
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct PostgresClosure *pg;
+ struct TALER_MINTDB_Plugin *plugin;
+
+ pg = GNUNET_new (struct PostgresClosure);
+
+ if (0 != pthread_key_create (&pg->db_conn_threadlocal,
+ &db_conn_destroy))
+ {
+ LOG_ERROR ("Cannnot create pthread key.\n");
+ return NULL;
+ }
+ /* FIXME: use configuration section with "postgres" in its name... */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "mint", "db",
+ &pg->TALER_MINT_db_connection_cfg_str))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "db");
+ return NULL;
+ }
+ plugin = GNUNET_new (struct TALER_MINTDB_Plugin);
+ plugin->cls = pg;
+
+ return plugin;
}
-/* end of mint_db.c */
+/**
+ * Shutdown Postgres database subsystem.
+ *
+ * @param cls a `struct TALER_MINTDB_Plugin`
+ * @return NULL (always)
+ */
+void *
+libtaler_plugin_mintdb_postgres_done (void *cls)
+{
+ struct TALER_MINTDB_Plugin *plugin = cls;
+ struct PostgresClosure *pg = plugin->cls;
+
+ GNUNET_free (pg);
+ GNUNET_free (plugin);
+ return NULL;
+}
+
+/* end of plugin_mintdb_postgres.c */
diff --git a/src/mint/taler-mint-dbinit.c b/src/mint/taler-mint-dbinit.c
index 838f98e25..060eabc7b 100644
--- a/src/mint/taler-mint-dbinit.c
+++ b/src/mint/taler-mint-dbinit.c
@@ -22,7 +22,7 @@
#include
#include
#include "taler_util.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
/**
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
index 7903d5c1c..9adf26dfd 100644
--- a/src/mint/taler-mint-httpd.c
+++ b/src/mint/taler-mint-httpd.c
@@ -35,7 +35,7 @@
#include "taler-mint-httpd_withdraw.h"
#include "taler-mint-httpd_refresh.h"
#include "taler-mint-httpd_keystate.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
/**
@@ -260,16 +260,7 @@ mint_serve_process_config (const char *mint_directory)
GNUNET_free (master_pub_str);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint", "db",
- &db_cfg))
- {
- fprintf (stderr,
- "invalid configuration: mint.db\n");
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- TALER_MINT_DB_init (db_cfg))
+ TALER_MINT_plugin_load (cfg))
{
fprintf (stderr,
"failed to initialize DB subsystem\n");
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index 0c3675d38..292ef68fa 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -29,9 +29,9 @@
#include "taler-mint-httpd_db.h"
#include "taler_signatures.h"
#include "taler-mint-httpd_responses.h"
-#include "mint_db.h"
#include "taler_util.h"
#include "taler-mint-httpd_keystate.h"
+#include "plugin.h"
/**
@@ -48,7 +48,7 @@ int
TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
const struct Deposit *deposit)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct TALER_MINT_DB_TransactionList *tl;
struct TALER_MINT_DB_TransactionList *pos;
struct TALER_Amount spent;
@@ -59,14 +59,16 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
struct TALER_MINT_DenomKeyIssuePriv *dki;
int ret;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_YES ==
- TALER_MINT_DB_have_deposit (db_conn,
- deposit))
+ plugin->have_deposit (plugin->cls,
+ session,
+ deposit))
{
return TALER_MINT_reply_deposit_success (connection,
&deposit->coin.coin_pub,
@@ -88,13 +90,15 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
TALER_MINT_key_state_release (mks);
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- tl = TALER_MINT_DB_get_coin_transactions (db_conn,
- &deposit->coin.coin_pub);
+ tl = plugin->get_coin_transactions (plugin->cls,
+ session,
+ &deposit->coin.coin_pub);
spent = fee_deposit; /* fee for THIS transaction */
if (GNUNET_OK !=
TALER_amount_add (&spent,
@@ -155,7 +159,8 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
if (0 < TALER_amount_cmp (&spent,
&value))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
ret = TALER_MINT_reply_deposit_insufficient_funds (connection,
tl);
TALER_MINT_DB_free_coin_transaction_list (tl);
@@ -164,16 +169,19 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
TALER_MINT_DB_free_coin_transaction_list (tl);
if (GNUNET_OK !=
- TALER_MINT_DB_insert_deposit (db_conn,
- deposit))
+ plugin->insert_deposit (plugin->cls,
+ session,
+ deposit))
{
LOG_WARNING ("Failed to store /deposit information in database\n");
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/deposit transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
@@ -200,17 +208,19 @@ int
TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct ReserveHistory *rh;
int res;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- rh = TALER_MINT_DB_get_reserve_history (db_conn,
- reserve_pub);
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ reserve_pub);
if (NULL == rh)
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
@@ -245,7 +255,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
size_t blinded_msg_len,
const struct GNUNET_CRYPTO_EddsaSignature *signature)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct ReserveHistory *rh;
const struct ReserveHistory *pos;
struct MintKeyState *key_state;
@@ -266,14 +276,16 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
blinded_msg_len,
&h_blind);
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
- &h_blind,
- &collectable);
+ res = plugin->get_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ &collectable);
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
@@ -305,18 +317,21 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
"Denomination not found");
}
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_internal_db_error (connection);
}
- rh = TALER_MINT_DB_get_reserve_history (db_conn,
- reserve);
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ reserve);
if (NULL == rh)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
@@ -336,7 +351,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
&value,
&fee_withdraw))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_internal_db_error (connection);
}
@@ -356,7 +372,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
&deposit_total,
&pos->details.bank->amount))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_internal_db_error (connection);
}
@@ -375,7 +392,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
&withdraw_total,
&value))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_internal_db_error (connection);
}
@@ -392,7 +410,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
&balance))
{
TALER_MINT_key_state_release (key_state);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
res = TALER_MINT_reply_withdraw_sign_insufficient_funds (connection,
rh);
TALER_MINT_DB_free_reserve_history (rh);
@@ -408,7 +427,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
if (NULL == sig)
{
GNUNET_break (0);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_error (connection,
"Internal error");
}
@@ -420,18 +440,21 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
&collectable.h_coin_envelope);
collectable.reserve_sig = *signature;
if (GNUNET_OK !=
- TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
- &h_blind,
- amount_required,
- &collectable))
+ plugin->insert_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ amount_required,
+ &collectable))
{
GNUNET_break (0);
GNUNET_CRYPTO_rsa_signature_free (sig);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/withdraw/sign transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
@@ -448,7 +471,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
* the database.
*
* @param connection the connection to send errors to
- * @param db_conn the database connection
+ * @param session the database connection
* @param key_state the mint's key state
* @param session_pub the refresh session's public key
* @param coin_public_info the coin to melt
@@ -460,7 +483,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
*/
static int
refresh_accept_melts (struct MHD_Connection *connection,
- PGconn *db_conn,
+ struct TALER_MINTDB_Session *session,
const struct MintKeyState *key_state,
const struct GNUNET_HashCode *melt_hash,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
@@ -489,8 +512,9 @@ refresh_accept_melts (struct MHD_Connection *connection,
TALER_amount_ntoh (&coin_value,
&dki->value);
- tl = TALER_MINT_DB_get_coin_transactions (db_conn,
- &coin_public_info->coin_pub);
+ tl = plugin->get_coin_transactions (plugin->cls,
+ session,
+ &coin_public_info->coin_pub);
/* FIXME: #3636: compute how much value is left with this coin and
compare to `expected_value`! (subtract from "coin_value") */
coin_residual = coin_value;
@@ -518,10 +542,11 @@ refresh_accept_melts (struct MHD_Connection *connection,
melt.melt_hash = *melt_hash;
melt.amount = coin_details->melt_amount;
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_melt (db_conn,
- session_pub,
- oldcoin_index,
- &melt))
+ plugin->insert_refresh_melt (plugin->cls,
+ session,
+ session_pub,
+ oldcoin_index,
+ &melt))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -570,37 +595,42 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
struct RefreshCommitLink *const* commit_link)
{
struct MintKeyState *key_state;
- struct RefreshSession session;
- PGconn *db_conn;
+ struct RefreshSession refresh_session;
+ struct TALER_MINTDB_Session *session;
int res;
unsigned int i;
unsigned int j;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_refresh_session (db_conn,
- refresh_session_pub,
- &session);
+ res = plugin->get_refresh_session (plugin->cls,
+ session,
+ refresh_session_pub,
+ &refresh_session);
if (GNUNET_YES == res)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
res = TALER_MINT_reply_refresh_melt_success (connection,
- &session.session_hash,
- session.noreveal_index);
+ &refresh_session.session_hash,
+ refresh_session.noreveal_index);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
if (GNUNET_SYSERR == res)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
@@ -610,7 +640,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
{
if (GNUNET_OK !=
(res = refresh_accept_melts (connection,
- db_conn,
+ session,
key_state,
melt_hash,
refresh_session_pub,
@@ -619,7 +649,8 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
i)))
{
TALER_MINT_key_state_release (key_state);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
}
@@ -629,12 +660,14 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
for (i=0;iinsert_refresh_order (plugin->cls,
+ session,
+ refresh_session_pub,
+ i,
+ denom_pubs[i]))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
}
@@ -644,13 +677,15 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
for (j = 0; j < num_new_denoms; j++)
{
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_commit_coin (db_conn,
- refresh_session_pub,
- i,
- j,
- &commit_coin[i][j]))
+ plugin->insert_refresh_commit_coin (plugin->cls,
+ session,
+ refresh_session_pub,
+ i,
+ j,
+ &commit_coin[i][j]))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
}
@@ -660,13 +695,15 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
for (j = 0; j < coin_count; j++)
{
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_commit_link (db_conn,
- refresh_session_pub,
- i,
- j,
- &commit_link[i][j]))
+ plugin->insert_refresh_commit_link (plugin->cls,
+ session,
+ refresh_session_pub,
+ i,
+ j,
+ &commit_link[i][j]))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
}
@@ -674,34 +711,37 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
/* store 'global' session data */
- session.melt_sig = *client_signature;
- session.session_hash = *melt_hash;
- session.num_oldcoins = coin_count;
- session.num_newcoins = num_new_denoms;
- session.kappa = KAPPA; // FIXME...
- session.noreveal_index
+ refresh_session.melt_sig = *client_signature;
+ refresh_session.session_hash = *melt_hash;
+ refresh_session.num_oldcoins = coin_count;
+ refresh_session.num_newcoins = num_new_denoms;
+ refresh_session.kappa = KAPPA; // FIXME...
+ refresh_session.noreveal_index
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- session.kappa);
+ refresh_session.kappa);
if (GNUNET_OK !=
- (res = TALER_MINT_DB_create_refresh_session (db_conn,
- refresh_session_pub,
- &session)))
+ (res = plugin->create_refresh_session (plugin->cls,
+ session,
+ refresh_session_pub,
+ &refresh_session)))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/refresh/melt transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
}
return TALER_MINT_reply_refresh_melt_success (connection,
- &session.session_hash,
- session.noreveal_index);
+ &refresh_session.session_hash,
+ refresh_session.noreveal_index);
}
@@ -712,7 +752,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
* Then derives the shared secret for each kappa, and check that they match.
*
* @param connection the MHD connection to handle
- * @param db_conn database connection to use
+ * @param session database connection to use
* @param refresh_session session to query
* @param off commitment offset to check
* @param num_oldcoins size of the @a transfer_privs and @a melts arrays
@@ -726,7 +766,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
*/
static int
check_commitment (struct MHD_Connection *connection,
- PGconn *db_conn,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
unsigned int off,
unsigned int num_oldcoins,
@@ -749,11 +789,12 @@ check_commitment (struct MHD_Connection *connection,
struct TALER_LinkSecret shared_secret;
struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check;
- res = TALER_MINT_DB_get_refresh_commit_link (db_conn,
- refresh_session,
- off,
- j,
- &commit_link);
+ res = plugin->get_refresh_commit_link (plugin->cls,
+ session,
+ refresh_session,
+ off,
+ j,
+ &commit_link);
if (GNUNET_OK != res)
{
GNUNET_break (0);
@@ -842,11 +883,12 @@ check_commitment (struct MHD_Connection *connection,
char *buf;
size_t buf_len;
- res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
- refresh_session,
- off,
- j,
- &commit_coin);
+ res = plugin->get_refresh_commit_coin (plugin->cls,
+ session,
+ refresh_session,
+ off,
+ j,
+ &commit_coin);
if (GNUNET_OK != res)
{
GNUNET_break (0);
@@ -914,7 +956,7 @@ check_commitment (struct MHD_Connection *connection,
* envelope from the database and performs the signing operation.
*
* @param connection the MHD connection to handle
- * @param db_conn database connection to use
+ * @param session database connection to use
* @param refresh_session session to query
* @param key_state key state to lookup denomination pubs
* @param denom_pub denomination key for the coin to create
@@ -925,7 +967,7 @@ check_commitment (struct MHD_Connection *connection,
*/
static struct GNUNET_CRYPTO_rsa_Signature *
refresh_mint_coin (struct MHD_Connection *connection,
- PGconn *db_conn,
+ struct TALER_MINTDB_Session *session,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
struct MintKeyState *key_state,
const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub,
@@ -937,11 +979,12 @@ refresh_mint_coin (struct MHD_Connection *connection,
struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
int res;
- res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
- refresh_session,
- noreveal_index,
- coin_off,
- &commit_coin);
+ res = plugin->get_refresh_commit_coin (plugin->cls,
+ session,
+ refresh_session,
+ noreveal_index,
+ coin_off,
+ &commit_coin);
if (GNUNET_OK != res)
{
GNUNET_break (0);
@@ -962,10 +1005,11 @@ refresh_mint_coin (struct MHD_Connection *connection,
return NULL;
}
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_collectable (db_conn,
- refresh_session,
- coin_off,
- ev_sig))
+ plugin->insert_refresh_collectable (plugin->cls,
+ session,
+ refresh_session,
+ coin_off,
+ ev_sig))
{
GNUNET_break (0);
GNUNET_CRYPTO_rsa_signature_free (ev_sig);
@@ -997,7 +1041,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs)
{
int res;
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct RefreshSession refresh_session;
struct MintKeyState *key_state;
struct RefreshMelt *melts;
@@ -1007,15 +1051,17 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
unsigned int j;
unsigned int off;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_refresh_session (db_conn,
- refresh_session_pub,
- &refresh_session);
+ res = plugin->get_refresh_session (plugin->cls,
+ session,
+ refresh_session_pub,
+ &refresh_session);
if (GNUNET_NO == res)
return TALER_MINT_reply_arg_invalid (connection,
"session_pub");
@@ -1032,10 +1078,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
for (j=0;jget_refresh_melt (plugin->cls,
+ session,
+ refresh_session_pub,
+ j,
+ &melts[j]))
{
GNUNET_break (0);
GNUNET_free (melts);
@@ -1046,9 +1093,10 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *));
for (j=0;jget_refresh_order (plugin->cls,
+ session,
+ refresh_session_pub,
+ j);
if (NULL == denom_pubs[j])
{
GNUNET_break (0);
@@ -1069,7 +1117,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
off = 1;
if (GNUNET_OK !=
(res = check_commitment (connection,
- db_conn,
+ session,
refresh_session_pub,
i + off,
refresh_session.num_oldcoins,
@@ -1089,7 +1137,8 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
/* Client request OK, start transaction */
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
for (j=0;jcommit (plugin->cls,
+ session))
{
LOG_WARNING ("/refresh/reveal transaction commit failed\n");
for (i=0;iget_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_db_get_transfer (db_conn,
- coin_pub,
- &transfer_pub,
- &shared_secret_enc);
+ res = plugin->get_transfer (plugin->cls,
+ session,
+ coin_pub,
+ &transfer_pub,
+ &shared_secret_enc);
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
@@ -1190,7 +1242,9 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
}
GNUNET_assert (GNUNET_OK == res);
- ldl = TALER_db_get_link (db_conn, coin_pub);
+ ldl = plugin->get_link (plugin->cls,
+ session,
+ coin_pub);
if (NULL == ldl)
{
return TALER_MINT_reply_json_pack (connection,
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index a40e3ae22..dbfecccd1 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -25,7 +25,7 @@
#include
#include
#include "taler_util.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
/**
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c
index 37d6d23d5..e411e0d8e 100644
--- a/src/mint/taler-mint-httpd_deposit.c
+++ b/src/mint/taler-mint-httpd_deposit.c
@@ -32,7 +32,7 @@
#include
#include
#include
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "taler_signatures.h"
#include "taler_util.h"
#include "taler-mint-httpd_parsing.h"
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index e62521ef4..d4979288d 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -24,7 +24,7 @@
#include
#include
#include
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "taler_signatures.h"
#include "taler_util.h"
#include "taler-mint-httpd_parsing.h"
diff --git a/src/mint/taler-mint-reservemod.c b/src/mint/taler-mint-reservemod.c
index df3f0cd5d..958d234b1 100644
--- a/src/mint/taler-mint-reservemod.c
+++ b/src/mint/taler-mint-reservemod.c
@@ -24,7 +24,7 @@
#include
#include "taler_util.h"
#include "taler_signatures.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "db_pq.h"
diff --git a/src/mint/taler_mintdb_plugin.h b/src/mint/taler_mintdb_plugin.h
new file mode 100644
index 000000000..d330b817b
--- /dev/null
+++ b/src/mint/taler_mintdb_plugin.h
@@ -0,0 +1,1002 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ 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, If not, see
+*/
+/**
+ * @file mint/mint_db.h
+ * @brief Low-level (statement-level) database access for the mint
+ * @author Florian Dold
+ * @author Christian Grothoff
+ */
+#ifndef MINT_DB_H
+#define MINT_DB_H
+
+#include
+#include "taler_util.h"
+
+
+/**
+ * Information we keep on bank transfer(s) that established a reserve.
+ */
+struct BankTransfer
+{
+
+ /**
+ * Public key of the reserve that was filled.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+
+ /**
+ * Amount that was transferred to the mint.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Detailed wire information about the transaction.
+ */
+ const json_t *wire;
+
+};
+
+
+/**
+ * A summary of a Reserve
+ */
+struct Reserve
+{
+ /**
+ * The reserve's public key. This uniquely identifies the reserve
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey *pub;
+
+ /**
+ * The balance amount existing in the reserve
+ */
+ struct TALER_Amount balance;
+
+ /**
+ * The expiration date of this reserve
+ */
+ struct GNUNET_TIME_Absolute expiry;
+};
+
+
+/**
+ * Information we keep for a withdrawn coin to reproduce
+ * the /withdraw operation if needed, and to have proof
+ * that a reserve was drained by this amount.
+ */
+struct CollectableBlindcoin
+{
+
+ /**
+ * Our signature over the (blinded) coin.
+ */
+ struct GNUNET_CRYPTO_rsa_Signature *sig;
+
+ /**
+ * Denomination key (which coin was generated).
+ */
+ struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
+
+ /**
+ * Public key of the reserve that was drained.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+
+ /**
+ * Hash over the blinded message, needed to verify
+ * the @e reserve_sig.
+ */
+ struct GNUNET_HashCode h_coin_envelope;
+
+ /**
+ * Signature confirming the withdrawl, matching @e reserve_pub,
+ * @e denom_pub and @e h_coin_envelope.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
+};
+
+
+
+/**
+ * Types of operations on a reserved.
+ */
+enum TALER_MINT_DB_ReserveOperation
+{
+ /**
+ * Money was deposited into the reserve via a bank transfer.
+ */
+ TALER_MINT_DB_RO_BANK_TO_MINT = 0,
+
+ /**
+ * A Coin was withdrawn from the reserve using /withdraw.
+ */
+ TALER_MINT_DB_RO_WITHDRAW_COIN = 1
+};
+
+
+/**
+ * Reserve history as a linked list. Lists all of the transactions
+ * associated with this reserve (such as the bank transfers that
+ * established the reserve and all /withdraw operations we have done
+ * since).
+ */
+struct ReserveHistory
+{
+
+ /**
+ * Next entry in the reserve history.
+ */
+ struct ReserveHistory *next;
+
+ /**
+ * Type of the event, determins @e details.
+ */
+ enum TALER_MINT_DB_ReserveOperation type;
+
+ /**
+ * Details of the operation, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details about a bank transfer to the mint.
+ */
+ struct BankTransfer *bank;
+
+ /**
+ * Details about a /withdraw operation.
+ */
+ struct CollectableBlindcoin *withdraw;
+
+ } details;
+
+};
+
+
+/**
+ * Specification for a /deposit operation.
+ */
+struct Deposit
+{
+ /**
+ * Information about the coin that is being deposited.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * ECDSA signature affirming that the customer intends
+ * this coin to be deposited at the merchant identified
+ * by @e h_wire in relation to the contract identified
+ * by @e h_contract.
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature csig;
+
+ /**
+ * Public key of the merchant. Enables later identification
+ * of the merchant in case of a need to rollback transactions.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
+
+ /**
+ * Hash over the contract between merchant and customer
+ * (remains unknown to the Mint).
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Hash of the (canonical) representation of @e wire, used
+ * to check the signature on the request. Generated by
+ * the mint from the detailed wire data provided by the
+ * merchant.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Detailed wire information for executing the transaction.
+ */
+ const json_t *wire;
+
+ /**
+ * Merchant-generated transaction ID to detect duplicate
+ * transactions.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Fraction of the coin's remaining value to be deposited.
+ * The coin is identified by @e coin_pub.
+ */
+ struct TALER_Amount amount;
+
+};
+
+
+/**
+ * Global information for a refreshing session. Includes
+ * dimensions of the operation, security parameters and
+ * client signatures from "/refresh/melt" and "/refresh/commit".
+ */
+struct RefreshSession
+{
+ /**
+ * Signature over the commitments by the client,
+ * only valid if @e has_commit_sig is set.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature commit_sig;
+
+ /**
+ * Hash over coins to melt and coins to create of the
+ * refresh session.
+ */
+ struct GNUNET_HashCode session_hash;
+
+ /**
+ * Signature over the melt by the client.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature melt_sig;
+
+ /**
+ * Number of coins we are melting.
+ */
+ uint16_t num_oldcoins;
+
+ /**
+ * Number of new coins we are creating.
+ */
+ uint16_t num_newcoins;
+
+ /**
+ * Number of parallel operations we perform for the cut and choose.
+ * (must be greater or equal to three for security). 0 if not yet
+ * known.
+ */
+ uint16_t kappa;
+
+ /**
+ * Index (smaller @e kappa) which the mint has chosen to not
+ * have revealed during cut and choose.
+ */
+ uint16_t noreveal_index;
+
+};
+
+
+/**
+ * Specification for coin in a /refresh/melt operation.
+ */
+struct RefreshMelt
+{
+ /**
+ * Information about the coin that is being melted.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * Signature over the melting operation.
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
+
+ /**
+ * Which melting operation should the coin become a part of.
+ */
+ struct GNUNET_HashCode melt_hash;
+
+ /**
+ * How much value is being melted?
+ * This amount includes the fees, so the final amount contributed
+ * to the melt is this value minus the fee for melting the coin.
+ */
+ struct TALER_Amount amount;
+
+};
+
+
+/**
+ * We have as many `struct RefreshCommitCoin` as there are new
+ * coins being created by the refresh (for each of the kappa
+ * sets). These are the coins we ask the mint to sign if the
+ * respective set is selected.
+ */
+struct RefreshCommitCoin
+{
+
+ /**
+ * Encrypted data allowing those able to decrypt it to derive
+ * the private keys of the new coins created by the refresh.
+ */
+ struct TALER_RefreshLinkEncrypted *refresh_link;
+
+ /**
+ * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
+ */
+ char *coin_ev;
+
+ /**
+ * Number of bytes in @e coin_ev.
+ */
+ size_t coin_ev_size;
+
+};
+
+
+/**
+ * For each (old) coin being melted, we have a `struct
+ * RefreshCommitLink` that allows the user to find the shared secret
+ * to decrypt the respective refresh links for the new coins in the
+ * `struct RefreshCommitCoin`.
+ */
+struct RefreshCommitLink
+{
+ /**
+ * Transfer public key (FIXME: explain!)
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
+
+ /**
+ * Encrypted shared secret to decrypt the link.
+ */
+ struct TALER_EncryptedLinkSecret shared_secret_enc;
+};
+
+
+/**
+ * Linked list of refresh information linked to a coin.
+ */
+struct LinkDataList
+{
+ /**
+ * Information is stored in a NULL-terminated linked list.
+ */
+ struct LinkDataList *next;
+
+ /**
+ * Link data, used to recover the private key of the coin
+ * by the owner of the old coin.
+ */
+ struct TALER_RefreshLinkEncrypted *link_data_enc;
+
+ /**
+ * Denomination public key, determines the value of the coin.
+ */
+ struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
+
+ /**
+ * Signature over the blinded envelope.
+ */
+ struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
+};
+
+
+/**
+ * Specification for a /lock operation.
+ */
+struct Lock
+{
+ /**
+ * Information about the coin that is being melted.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * Signature over the melting operation.
+ */
+ const struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
+
+ /**
+ * How much value is being melted?
+ */
+ struct TALER_Amount amount;
+
+ // FIXME: more needed...
+};
+
+
+/**
+ * Enumeration to classify the different types of transactions
+ * that can be done with a coin.
+ */
+enum TALER_MINT_DB_TransactionType
+{
+ /**
+ * /deposit operation.
+ */
+ TALER_MINT_DB_TT_DEPOSIT = 0,
+
+ /**
+ * /refresh/melt operation.
+ */
+ TALER_MINT_DB_TT_REFRESH_MELT = 1,
+
+ /**
+ * /lock operation.
+ */
+ TALER_MINT_DB_TT_LOCK = 2
+};
+
+
+/**
+ * List of transactions we performed for a particular coin.
+ */
+struct TALER_MINT_DB_TransactionList
+{
+
+ /**
+ * Next pointer in the NULL-terminated linked list.
+ */
+ struct TALER_MINT_DB_TransactionList *next;
+
+ /**
+ * Type of the transaction, determines what is stored in @e details.
+ */
+ enum TALER_MINT_DB_TransactionType type;
+
+ /**
+ * Details about the transaction, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details if transaction was a /deposit operation.
+ */
+ struct Deposit *deposit;
+
+ /**
+ * Details if transaction was a /refresh/melt operation.
+ */
+ struct RefreshMelt *melt;
+
+ /**
+ * Details if transaction was a /lock operation.
+ */
+ struct Lock *lock;
+
+ } details;
+
+};
+
+
+/**
+ * Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_MINTDB_Session;
+
+
+/**
+ * The plugin API, returned from the plugin's "init" function.
+ * The argument given to "init" is simply a configuration handle.
+ */
+struct TALER_MINTDB_Plugin
+{
+
+ /**
+ * Closure for all callbacks.
+ */
+ void *cls;
+
+ /**
+ * Get the thread-local database-handle.
+ * Connect to the db if the connection does not exist yet.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
+ * database default one
+ * @param the database connection, or NULL on error
+ */
+ struct TALER_MINTDB_Session *
+ (*get_session) (void *cls,
+ int temporary);
+
+
+ /**
+ * Drop the temporary taler schema. This is only useful for testcases.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*drop_temporary) (void *cls,
+ struct TALER_MINTDB_Session *db);
+
+
+ /**
+ * Create the necessary tables if they are not present
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary should we use a temporary schema
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*create_tables) (void *cls,
+ int temporary);
+
+
+ /**
+ * Start a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn connection to use
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*start) (void *cls,
+ struct TALER_MINTDB_Session *db_conn);
+
+
+ /**
+ * Commit a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn connection to use
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*commit) (void *cls,
+ struct TALER_MINTDB_Session *db_conn);
+
+
+ /**
+ * Abort/rollback a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn connection to use
+ */
+ void
+ (*rollback) (void *cls,
+ struct TALER_MINTDB_Session *db_conn);
+
+
+ /**
+ * Get the summary of a reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param reserve the reserve data. The public key of the reserve should be set
+ * in this structure; it is used to query the database. The balance
+ * and expiration are then filled accordingly.
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*reserve_get) (void *cls,
+ struct TALER_MINTDB_Session *db,
+ struct Reserve *reserve);
+
+ /* FIXME: add functions to add bank transfers to our DB
+ (and to test if we already did add one) (#3633/#3717) */
+
+
+ /**
+ * Insert a incoming transaction into reserves. New reserves are also created
+ * through this function.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param reserve the reserve structure. The public key of the reserve should
+ * be set here. Upon successful execution of this function, the
+ * balance and expiration of the reserve will be updated.
+ * @param balance the amount that has to be added to the reserve
+ * @param expiry the new expiration time for the reserve
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
+ */
+ int
+ (*reserves_in_insert) (void *cls,
+ struct TALER_MINTDB_Session *db,
+ struct Reserve *reserve,
+ const struct TALER_Amount *balance,
+ const struct GNUNET_TIME_Absolute expiry);
+
+
+ /**
+ * Locate the response for a /withdraw request under the
+ * key of the hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param h_blind hash of the blinded message
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*get_collectable_blindcoin) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_HashCode *h_blind,
+ struct CollectableBlindcoin *collectable);
+
+
+ /**
+ * Store collectable bit coin under the corresponding
+ * hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param h_blind hash of the blinded message
+ * @param withdraw amount by which the reserve will be withdrawn with this
+ * transaction
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*insert_collectable_blindcoin) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_Amount withdraw,
+ const struct CollectableBlindcoin *collectable);
+
+
+ /**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+ struct ReserveHistory *
+ (*get_reserve_history) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
+
+
+ /**
+ * Check if we have the specified deposit already in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param deposit deposit to search for
+ * @return #GNUNET_YES if we know this operation,
+ * #GNUNET_NO if this deposit is unknown to us,
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*have_deposit) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct Deposit *deposit);
+
+
+ /**
+ * Insert information about deposited coin into the
+ * database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn connection to the database
+ * @param deposit deposit information to store
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_deposit) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct Deposit *deposit);
+
+
+ /**
+ * Lookup refresh session data under the given public key.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database handle to use
+ * @param refresh_session_pub public key to use for the lookup
+ * @param refresh_session[OUT] where to store the result
+ * @return #GNUNET_YES on success,
+ * #GNUNET_NO if not found,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*get_refresh_session) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ struct RefreshSession *refresh_session);
+
+
+ /**
+ * Store new refresh session data under the given public key.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database handle to use
+ * @param refresh_session_pub public key to use to locate the session
+ * @param refresh_session session data to store
+ * @return #GNUNET_YES on success,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*create_refresh_session) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ const struct RefreshSession *refresh_session);
+
+
+
+ /**
+ * Store the given /refresh/melt request in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param refresh_session session key of the melt operation
+ * @param oldcoin_index index of the coin to store
+ * @param melt coin melt operation details to store
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_melt) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ uint16_t oldcoin_index,
+ const struct RefreshMelt *melt);
+
+
+ /**
+ * Get information about melted coin details from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param refresh_session session key of the melt operation
+ * @param oldcoin_index index of the coin to retrieve
+ * @param melt melt data to fill in
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*get_refresh_melt) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ uint16_t oldcoin_index,
+ struct RefreshMelt *melt);
+
+
+ /**
+ * Store in the database which coin(s) we want to create
+ * in a given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param session_pub refresh session key
+ * @param newcoin_index index of the coin to generate
+ * @param denom_pub denomination of the coin to create
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_order) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index,
+ const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub);
+
+
+ /**
+ * Lookup in the database the @a newcoin_index coin that we want to
+ * create in the given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param session_pub refresh session key
+ * @param newcoin_index index of the coin to generate
+ * @param denom_pub denomination of the coin to create
+ * @return NULL on error (not found or internal error)
+ */
+ struct GNUNET_CRYPTO_rsa_PublicKey *
+ (*get_refresh_order) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index);
+
+
+ /**
+ * Store information about the commitment of the
+ * given coin for the given refresh session in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param refresh_session_pub refresh session this commitment belongs to
+ * @param i set index (1st dimension)
+ * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
+ * @param commit_coin coin commitment to store
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_refresh_commit_coin) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ const struct RefreshCommitCoin *commit_coin);
+
+
+ /**
+ * Obtain information about the commitment of the
+ * given coin of the given refresh session from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param refresh_session_pub refresh session the commitment belongs to
+ * @param i set index (1st dimension)
+ * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
+ * @param commit_coin[OUT] coin commitment to return
+ * @return #GNUNET_OK on success
+ * #GNUNET_NO if not found
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*get_refresh_commit_coin) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ struct RefreshCommitCoin *commit_coin);
+
+
+ /**
+ * Store the commitment to the given (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param refresh_session_pub public key of the refresh session this
+ * commitment belongs with
+ * @param i set index (1st dimension)
+ * @param j coin index (2nd dimension), corresponds to melted (old) coins
+ * @param commit_link link information to store
+ * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_commit_link) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ const struct RefreshCommitLink *commit_link);
+
+ /**
+ * Obtain the commited (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection to use
+ * @param refresh_session_pub public key of the refresh session this
+ * commitment belongs with
+ * @param i set index (1st dimension)
+ * @param j coin index (2nd dimension), corresponds to melted (old) coins
+ * @param cc[OUT] link information to return
+ * @return #GNUNET_SYSERR on internal error,
+ * #GNUNET_NO if commitment was not found
+ * #GNUNET_OK on success
+ */
+ int
+ (*get_refresh_commit_link) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
+ unsigned int i,
+ unsigned int j,
+ struct RefreshCommitLink *cc);
+
+
+ /**
+ * Insert signature of a new coin generated during refresh into
+ * the database indexed by the refresh session and the index
+ * of the coin. This data is later used should an old coin
+ * be used to try to obtain the private keys during "/refresh/link".
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param session_pub refresh session
+ * @param newcoin_index coin index
+ * @param ev_sig coin signature
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_collectable) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ uint16_t newcoin_index,
+ const struct GNUNET_CRYPTO_rsa_Signature *ev_sig);
+
+
+ /**
+ * Obtain the link data of a coin, that is the encrypted link
+ * information, the denomination keys and the signatures.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param coin_pub public key to use to retrieve linkage data
+ * @return all known link data for the coin
+ */
+ struct LinkDataList *
+ (*get_link) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
+
+
+ /**
+ * Obtain shared secret and transfer public key from the public key of
+ * the coin. This information and the link information returned by
+ * #TALER_db_get_link() enable the owner of an old coin to determine
+ * the private keys of the new coins after the melt.
+ *
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param coin_pub public key of the coin
+ * @param transfer_pub[OUT] public transfer key
+ * @param shared_secret_enc[OUT] set to shared secret
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure (not found)
+ * #GNUNET_SYSERR on internal failure (database issue)
+ */
+ int
+ (*get_transfer) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
+ struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
+ struct TALER_EncryptedLinkSecret *shared_secret_enc);
+
+
+ /**
+ * Test if the given /lock request is known to us.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param lock lock operation
+ * @return #GNUNET_YES if known,
+ * #GNUENT_NO if not,
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*have_lock) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct Lock *lock);
+
+
+ /**
+ * Store the given /lock request in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param lock lock operation
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_lock) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct Lock *lock);
+
+
+ /**
+ * Compile a list of all (historic) transactions performed
+ * with the given coin (/refresh/melt and /deposit operations).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db_conn database connection
+ * @param coin_pub coin to investigate
+ * @return list of transactions, NULL if coin is fresh
+ */
+ struct TALER_MINT_DB_TransactionList *
+ (*get_coin_transactions) (void *cls,
+ struct TALER_MINTDB_Session *db_conn,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
+
+};
+
+
+#endif /* _NEURO_MINT_DB_H */
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index a15d42ad8..07c120c50 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -8,7 +8,8 @@ libtalerutil_la_SOURCES = \
amount.c \
crypto.c \
util.c \
- json.c
+ json.c \
+ os_installation.c
libtalerutil_la_LIBADD = \
-lgnunetutil \
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
new file mode 100644
index 000000000..82dc49180
--- /dev/null
+++ b/src/util/os_installation.c
@@ -0,0 +1,701 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2006-2014 Christian Grothoff (and other contributing authors)
+
+ GNUnet 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.
+
+ GNUnet 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 GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file os_installation.c
+ * @brief get paths used by the program; based heavily on the
+ * corresponding GNUnet file, just adapted for Taler.
+ * @author Milan
+ */
+#include "platform.h"
+#include
+#if DARWIN
+#include
+#include
+#elif WINDOWS
+#include
+#endif
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+
+#if LINUX
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_maps ()
+{
+ char fn[64];
+ char line[1024];
+ char dir[1024];
+ FILE *f;
+ char *lgu;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
+ if (NULL == (f = FOPEN (fn, "r")))
+ return NULL;
+ while (NULL != fgets (line, sizeof (line), f))
+ {
+ if ((1 ==
+ SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
+ (NULL != (lgu = strstr (dir, "libtalerutil"))))
+ {
+ lgu[0] = '\0';
+ FCLOSE (f);
+ return GNUNET_strdup (dir);
+ }
+ }
+ FCLOSE (f);
+ return NULL;
+}
+
+
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_exe ()
+{
+ char fn[64];
+ char lnk[1024];
+ ssize_t size;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
+ size = readlink (fn, lnk, sizeof (lnk) - 1);
+ if (size <= 0)
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
+ return NULL;
+ }
+ GNUNET_assert (size < sizeof (lnk));
+ lnk[size] = '\0';
+ while ((lnk[size] != '/') && (size > 0))
+ size--;
+ /* test for being in lib/taler/libexec/ or lib/MULTIARCH/taler/libexec */
+ if ( (size > strlen ("/taler/libexec/")) &&
+ (0 == strcmp ("/taler/libexec/",
+ &lnk[size - strlen ("/taler/libexec/")])) )
+ size -= strlen ("taler/libexec/");
+ if ((size < 4) || (lnk[size - 4] != '/'))
+ {
+ /* not installed in "/bin/" -- binary path probably useless */
+ return NULL;
+ }
+ lnk[size] = '\0';
+ return GNUNET_strdup (lnk);
+}
+#endif
+
+
+#if WINDOWS
+static HINSTANCE dll_instance;
+
+
+/**
+ * GNUNET_util_cl_init() in common_logging.c is preferred.
+ * This function is only for thread-local storage (not used in GNUnet)
+ * and hInstance saving.
+ */
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ dll_instance = hinstDLL;
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Try to determine path with win32-specific function
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_module_filename ()
+{
+ size_t pathlen = 512;
+ DWORD real_pathlen;
+ wchar_t *idx;
+ wchar_t *modulepath = NULL;
+ char *upath;
+ uint8_t *u8_string;
+ size_t u8_string_length;
+
+ /* This braindead function won't tell us how much space it needs, so
+ * we start at 1024 and double the space up if it doesn't fit, until
+ * it fits, or we exceed the threshold.
+ */
+ do
+ {
+ pathlen = pathlen * 2;
+ modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
+ SetLastError (0);
+ real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
+ } while (real_pathlen >= pathlen && pathlen < 16*1024);
+ if (real_pathlen >= pathlen)
+ GNUNET_assert (0);
+ /* To be safe */
+ modulepath[real_pathlen] = '\0';
+
+ idx = modulepath + real_pathlen;
+ while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
+ idx--;
+ *idx = L'\0';
+
+ /* Now modulepath holds full path to the directory where libtalerutil is.
+ * This directory should look like /bin or .
+ */
+ if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
+ {
+ /* At least one directory component (i.e. we're not in a root directory) */
+ wchar_t *dirname = idx;
+ while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
+ dirname--;
+ *dirname = L'\0';
+ if (dirname > modulepath)
+ {
+ dirname++;
+ /* Now modulepath holds full path to the parent directory of the directory
+ * where libtalerutil is.
+ * dirname holds the name of the directory where libtalerutil is.
+ */
+ if (wcsicmp (dirname, L"bin") == 0)
+ {
+ /* pass */
+ }
+ else
+ {
+ /* Roll back our changes to modulepath */
+ dirname--;
+ *dirname = L'/';
+ }
+ }
+ }
+
+ /* modulepath is TALER_PREFIX */
+ u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
+ if (NULL == u8_string)
+ GNUNET_assert (0);
+
+ upath = GNUNET_malloc (u8_string_length + 1);
+ memcpy (upath, u8_string, u8_string_length);
+ upath[u8_string_length] = '\0';
+
+ free (u8_string);
+ GNUNET_free (modulepath);
+
+ return upath;
+}
+#endif
+
+
+#if DARWIN
+/**
+ * Signature of the '_NSGetExecutablePath" function.
+ *
+ * @param buf where to write the path
+ * @param number of bytes available in 'buf'
+ * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
+ */
+typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
+
+
+/**
+ * Try to obtain the path of our executable using '_NSGetExecutablePath'.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_NSGetExecutablePath ()
+{
+ static char zero = '\0';
+ char *path;
+ size_t len;
+ MyNSGetExecutablePathProto func;
+
+ path = NULL;
+ if (NULL == (func =
+ (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
+ return NULL;
+ path = &zero;
+ len = 0;
+ /* get the path len, including the trailing \0 */
+ (void) func (path, &len);
+ if (0 == len)
+ return NULL;
+ path = GNUNET_malloc (len);
+ if (0 != func (path, &len))
+ {
+ GNUNET_free (path);
+ return NULL;
+ }
+ len = strlen (path);
+ while ((path[len] != '/') && (len > 0))
+ len--;
+ path[len] = '\0';
+ return path;
+}
+
+
+/**
+ * Try to obtain the path of our executable using '_dyld_image' API.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_dyld_image ()
+{
+ const char *path;
+ char *p;
+ char *s;
+ unsigned int i;
+ int c;
+
+ c = _dyld_image_count ();
+ for (i = 0; i < c; i++)
+ {
+ if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
+ continue;
+ path = _dyld_get_image_name (i);
+ if ( (NULL == path) || (0 == strlen (path)) )
+ continue;
+ p = GNUNET_strdup (path);
+ s = p + strlen (p);
+ while ((s > p) && ('/' != *s))
+ s--;
+ s++;
+ *s = '\0';
+ return p;
+ }
+ return NULL;
+}
+#endif
+
+
+/**
+ * Return the actual path to a file found in the current
+ * PATH environment variable.
+ *
+ * @param binary the name of the file to find
+ * @return path to binary, NULL if not found
+ */
+static char *
+get_path_from_PATH (const char *binary)
+{
+ char *path;
+ char *pos;
+ char *end;
+ char *buf;
+ const char *p;
+
+ if (NULL == (p = getenv ("PATH")))
+ return NULL;
+#if WINDOWS
+ /* On W32 look in CWD first. */
+ GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
+#else
+ path = GNUNET_strdup (p); /* because we write on it */
+#endif
+ buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
+ pos = path;
+ while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
+ {
+ *end = '\0';
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ pos = end + 1;
+ }
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_YES == GNUNET_DISK_file_test (buf))
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return NULL;
+}
+
+
+/**
+ * Try to obtain the installation path using the "TALER_PREFIX" environment
+ * variable.
+ *
+ * @return NULL on error (environment variable not set)
+ */
+static char *
+get_path_from_TALER_PREFIX ()
+{
+ const char *p;
+
+ if (NULL != (p = getenv ("TALER_PREFIX")))
+ return GNUNET_strdup (p);
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to Taler bin/ or lib/, prefering the lib/ path
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_taler_path ()
+{
+ char *ret;
+
+ if (NULL != (ret = get_path_from_TALER_PREFIX ()))
+ return ret;
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_maps ()))
+ return ret;
+ /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_dyld_image ()))
+ return ret;
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ /* other attempts here */
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not determine installation path for %s. Set `%s' environment variable.\n"),
+ "Taler", "TALER_PREFIX");
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to current app's bin/
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_exec_path ()
+{
+ char *ret = NULL;
+
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ /* other attempts here */
+ return ret;
+}
+
+
+/**
+ * @brief get the path to a specific Taler installation directory or,
+ * with #TALER_OS_IPK_SELF_PREFIX, the current running apps installation directory
+ * @author Milan
+ * @return a pointer to the dir path (to be freed by the caller)
+ */
+char *
+TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
+{
+ size_t n;
+ const char *dirname;
+ char *execpath = NULL;
+ char *tmp;
+ char *multiarch;
+ char *libdir;
+ int isbasedir;
+
+ /* if wanted, try to get the current app's bin/ */
+ if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
+ execpath = os_get_exec_path ();
+
+ /* try to get Taler's bin/ or lib/, or if previous was unsuccessful some
+ * guess for the current app */
+ if (NULL == execpath)
+ execpath = os_get_taler_path ();
+
+ if (NULL == execpath)
+ return NULL;
+
+ n = strlen (execpath);
+ if (0 == n)
+ {
+ /* should never happen, but better safe than sorry */
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ /* remove filename itself */
+ while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
+ execpath[--n] = '\0';
+
+ isbasedir = 1;
+ if ((n > 6) &&
+ ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
+ (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
+ {
+ if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
+ (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
+ {
+ /* strip '/lib32' or '/lib64' */
+ execpath[n - 6] = '\0';
+ n -= 6;
+ }
+ else
+ isbasedir = 0;
+ }
+ else if ((n > 4) &&
+ ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
+ (0 == strcasecmp (&execpath[n - 4], "/lib"))))
+ {
+ /* strip '/bin' or '/lib' */
+ execpath[n - 4] = '\0';
+ n -= 4;
+ }
+ multiarch = NULL;
+ if (NULL != (libdir = strstr (execpath, "/lib/")))
+ {
+ /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
+ here we need to re-add 'multiarch' to lib and libexec paths later! */
+ multiarch = &libdir[5];
+ if (NULL == strchr (multiarch, '/'))
+ libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
+ else
+ multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
+ }
+ /* in case this was a directory named foo-bin, remove "foo-" */
+ while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
+ execpath[--n] = '\0';
+ switch (dirkind)
+ {
+ case GNUNET_OS_IPK_PREFIX:
+ case GNUNET_OS_IPK_SELF_PREFIX:
+ dirname = DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_BINDIR:
+ dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBDIR:
+ if (isbasedir)
+ {
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib",
+ (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
+ (NULL != multiarch) ? multiarch : "",
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ }
+ dirname = DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DATADIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LOCALEDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_ICONDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DOCDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
+ "gnunet" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBEXECDIR:
+ if (isbasedir)
+ {
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
+ (NULL != multiarch) ? multiarch : "",
+ dirname);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+
+ GNUNET_free (tmp);
+ }
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ break;
+ default:
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ GNUNET_free (execpath);
+ return tmp;
+}
+
+
+/**
+ * Given the name of a taler-helper, taler-service or taler-daemon
+ * binary, try to prefix it with the libexec/-directory to get the
+ * full path.
+ *
+ * @param progname name of the binary
+ * @return full path to the binary, if possible, otherwise copy of 'progname'
+ */
+char *
+TALER_OS_get_libexec_binary_path (const char *progname)
+{
+ static char *cache;
+ char *libexecdir;
+ char *binary;
+
+ if ( (DIR_SEPARATOR == progname[0]) ||
+ (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
+ return GNUNET_strdup (progname);
+ if (NULL != cache)
+ libexecdir = cache;
+ else
+ libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
+ if (NULL == libexecdir)
+ return GNUNET_strdup (progname);
+ GNUNET_asprintf (&binary,
+ "%s%s",
+ libexecdir,
+ progname);
+ cache = libexecdir;
+ return binary;
+}
+
+
+
+/* end of os_installation.c */