From 39db1ae5dbbd12c0f452cfa56119d9a95f9b1b22 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 20 Jun 2017 13:40:17 +0200 Subject: address #5010 for /refresh/link --- src/exchangedb/plugin_exchangedb_postgres.c | 229 +++++++++++++++++----------- src/exchangedb/test_exchangedb.c | 11 +- 2 files changed, 151 insertions(+), 89 deletions(-) (limited to 'src/exchangedb') diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index b029db587..b11eec16d 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3895,45 +3895,38 @@ postgres_insert_refresh_out (void *cls, /** - * Obtain the link data of a coin, that is the encrypted link - * information, the denomination keys and the signatures. - * - * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param session database connection - * @param session_hash refresh session to get linkage data for - * @return all known link data for the session + * Closure for #add_ldl(). */ -static struct TALER_EXCHANGEDB_LinkDataList * -postgres_get_link_data_list (void *cls, - struct TALER_EXCHANGEDB_Session *session, - const struct GNUNET_HashCode *session_hash) +struct LinkDataContext { + /** + * List we are building. + */ struct TALER_EXCHANGEDB_LinkDataList *ldl; - int nrows; - struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (session_hash), - GNUNET_PQ_query_param_end - }; - PGresult *result; - result = GNUNET_PQ_exec_prepared (session->conn, - "get_link", - params); - ldl = NULL; - if (PGRES_TUPLES_OK != PQresultStatus (result)) - { - BREAK_DB_ERR (result, session->conn); - PQclear (result); - return NULL; - } - nrows = PQntuples (result); - if (0 == nrows) - { - PQclear (result); - return NULL; - } + /** + * Status, set to #GNUNET_SYSERR on errors, + */ + int status; +}; + - for (int i = nrows-1; i >= 0; i--) +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct LinkDataContext *` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +add_ldl (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct LinkDataContext *ldc = cls; + + for (int i = num_results - 1; i >= 0; i--) { struct GNUNET_CRYPTO_RsaPublicKey *denom_pub; struct GNUNET_CRYPTO_RsaSignature *sig; @@ -3954,71 +3947,98 @@ postgres_get_link_data_list (void *cls, rs, i)) { - PQclear (result); GNUNET_break (0); common_free_link_data_list (cls, - ldl); + ldc->ldl); + ldc->ldl = NULL; GNUNET_free (pos); - return NULL; + ldc->status = GNUNET_SYSERR; + return; } } - pos->next = ldl; + pos->next = ldc->ldl; pos->denom_pub.rsa_public_key = denom_pub; pos->ev_sig.rsa_signature = sig; - ldl = pos; + ldc->ldl = pos; } - PQclear (result); - return ldl; } /** - * Obtain shared secret and transfer public key from the public key of - * the coin. This information and the link information returned by - * #postgres_get_link_data_list() enable the owner of an old coin to - * determine the private keys of the new coins after the melt. + * Obtain the link data of a coin, that is the encrypted link + * information, the denomination keys and the signatures. * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param session database connection - * @param coin_pub public key of the coin - * @param tdc function to call for each session the coin was melted into - * @param tdc_cls closure for @a tdc - * @return #GNUNET_OK on success, - * #GNUNET_NO on failure (not found) - * #GNUNET_SYSERR on internal failure (database issue) + * @param session_hash refresh session to get linkage data for + * @param[out] ldlp set to all known link data for the session + * @return transaction status code */ -static int -postgres_get_transfer (void *cls, - struct TALER_EXCHANGEDB_Session *session, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - TALER_EXCHANGEDB_TransferDataCallback tdc, - void *tdc_cls) +static enum GNUNET_DB_QueryStatus +postgres_get_link_data_list (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct GNUNET_HashCode *session_hash, + struct TALER_EXCHANGEDB_LinkDataList **ldlp) { + struct LinkDataContext ldc; struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_auto_from_type (session_hash), GNUNET_PQ_query_param_end }; - PGresult *result; - int nrows; + enum GNUNET_DB_QueryStatus qs; - result = GNUNET_PQ_exec_prepared (session->conn, - "get_transfer", - params); - if (PGRES_TUPLES_OK != - PQresultStatus (result)) - { - BREAK_DB_ERR (result, session->conn); - PQclear (result); - return GNUNET_SYSERR; - } - nrows = PQntuples (result); - if (0 == nrows) - { - /* no matches found */ - PQclear (result); - return GNUNET_NO; - } - for (int i=0;iconn, + "get_link", + params, + &add_ldl, + &ldc); + *ldlp = ldc.ldl; + if (GNUNET_OK != ldc.status) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} + + +/** + * Closure for #add_link(). + */ +struct AddLinkContext +{ + /** + * Function to call on each result. + */ + TALER_EXCHANGEDB_TransferDataCallback tdc; + + /** + * Closure for @e tdc. + */ + void *tdc_cls; + + /** + * Status code, set to #GNUNET_SYSERR on errors. + */ + int status; +}; + + +/** + * Function to be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct AddLinkContext *` + * @param result the postgres result + * @param num_result the number of results in @a result + */ +static void +add_link (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct AddLinkContext *alc = cls; + + for (unsigned int i=0;istatus = GNUNET_SYSERR; + return; } - tdc (tdc_cls, - &session_hash, - &transfer_pub); + alc->tdc (alc->tdc_cls, + &session_hash, + &transfer_pub); } - PQclear (result); - return GNUNET_OK; +} + + +/** + * Obtain shared secret and transfer public key from the public key of + * the coin. This information and the link information returned by + * #postgres_get_link_data_list() enable the owner of an old coin to + * determine the private keys of the new coins after the melt. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session database connection + * @param coin_pub public key of the coin + * @param tdc function to call for each session the coin was melted into + * @param tdc_cls closure for @a tdc + * @return statement execution status + */ +static enum GNUNET_DB_QueryStatus +postgres_get_transfer (void *cls, + struct TALER_EXCHANGEDB_Session *session, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + TALER_EXCHANGEDB_TransferDataCallback tdc, + void *tdc_cls) +{ + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (coin_pub), + GNUNET_PQ_query_param_end + }; + struct AddLinkContext al_ctx; + enum GNUNET_DB_QueryStatus qs; + + al_ctx.tdc = tdc; + al_ctx.tdc_cls = tdc_cls; + al_ctx.status = GNUNET_OK; + qs = GNUNET_PQ_eval_prepared_multi_select (session->conn, + "get_transfer", + params, + &add_link, + &al_ctx); + if (GNUNET_OK != al_ctx.status) + qs = GNUNET_DB_STATUS_HARD_ERROR; + return qs; } diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index 9a58a38ec..df730a07e 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -530,6 +530,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) struct TALER_DenominationSignature ev_sigs[MELT_NEW_COINS]; unsigned int cnt; int ret; + enum GNUNET_DB_QueryStatus qs; ret = GNUNET_SYSERR; memset (ev_sigs, 0, sizeof (ev_sigs)); @@ -695,9 +696,11 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) GNUNET_CRYPTO_rsa_signature_free (test_sig.rsa_signature); } - ldl = plugin->get_link_data_list (plugin->cls, - session, - &session_hash); + qs = plugin->get_link_data_list (plugin->cls, + session, + &session_hash, + &ldl); + FAILIF (0 >= qs); FAILIF (NULL == ldl); for (ldlp = ldl; NULL != ldlp; ldlp = ldlp->next) { @@ -742,7 +745,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session) int ok; ok = GNUNET_NO; - FAILIF (GNUNET_OK != + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->get_transfer (plugin->cls, session, &meltp->coin.coin_pub, -- cgit v1.2.3