Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2017, 2021 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-exchange-httpd_db.c
18 : * @brief Generic database operations for the exchange.
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <pthread.h>
23 : #include <jansson.h>
24 : #include <gnunet/gnunet_json_lib.h>
25 : #include "taler_json_lib.h"
26 : #include "taler_mhd_lib.h"
27 : #include "taler_exchangedb_lib.h"
28 : #include "taler-exchange-httpd_db.h"
29 : #include "taler-exchange-httpd_responses.h"
30 :
31 :
32 : enum GNUNET_DB_QueryStatus
33 0 : TEH_make_coin_known (const struct TALER_CoinPublicInfo *coin,
34 : struct MHD_Connection *connection,
35 : uint64_t *known_coin_id,
36 : MHD_RESULT *mhd_ret)
37 : {
38 : enum TALER_EXCHANGEDB_CoinKnownStatus cks;
39 : struct TALER_DenominationHashP h_denom_pub;
40 : struct TALER_AgeCommitmentHash age_hash;
41 :
42 : /* make sure coin is 'known' in database */
43 0 : cks = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
44 : coin,
45 : known_coin_id,
46 : &h_denom_pub,
47 : &age_hash);
48 0 : switch (cks)
49 : {
50 0 : case TALER_EXCHANGEDB_CKS_ADDED:
51 0 : return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
52 0 : case TALER_EXCHANGEDB_CKS_PRESENT:
53 0 : return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
54 0 : case TALER_EXCHANGEDB_CKS_SOFT_FAIL:
55 0 : return GNUNET_DB_STATUS_SOFT_ERROR;
56 0 : case TALER_EXCHANGEDB_CKS_HARD_FAIL:
57 : *mhd_ret
58 0 : = TALER_MHD_reply_with_error (connection,
59 : MHD_HTTP_INTERNAL_SERVER_ERROR,
60 : TALER_EC_GENERIC_DB_STORE_FAILED,
61 : NULL);
62 0 : return GNUNET_DB_STATUS_HARD_ERROR;
63 0 : case TALER_EXCHANGEDB_CKS_DENOM_CONFLICT:
64 : /* FIXME: insufficient_funds != denom conflict! See issue #7267, need new
65 : * strategy for evidence gathering */
66 0 : *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
67 : connection,
68 : TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY,
69 : &h_denom_pub,
70 : &coin->coin_pub);
71 0 : return GNUNET_DB_STATUS_HARD_ERROR;
72 0 : case TALER_EXCHANGEDB_CKS_AGE_CONFLICT:
73 : /* FIXME: insufficient_funds != Age conflict! See issue #7267, need new
74 : * strategy for evidence gathering */
75 0 : *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (
76 : connection,
77 : TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
78 : &h_denom_pub,
79 : &coin->coin_pub);
80 0 : return GNUNET_DB_STATUS_HARD_ERROR;
81 : }
82 0 : GNUNET_assert (0);
83 : return GNUNET_DB_STATUS_HARD_ERROR;
84 : }
85 :
86 :
87 : enum GNUNET_GenericReturnValue
88 0 : TEH_DB_run_transaction (struct MHD_Connection *connection,
89 : const char *name,
90 : enum TEH_MetricTypeRequest mt,
91 : MHD_RESULT *mhd_ret,
92 : TEH_DB_TransactionCallback cb,
93 : void *cb_cls)
94 : {
95 0 : if (NULL != mhd_ret)
96 0 : *mhd_ret = -1; /* set to invalid value, to help detect bugs */
97 0 : if (GNUNET_OK !=
98 0 : TEH_plugin->preflight (TEH_plugin->cls))
99 : {
100 0 : GNUNET_break (0);
101 0 : if (NULL != mhd_ret)
102 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
103 : MHD_HTTP_INTERNAL_SERVER_ERROR,
104 : TALER_EC_GENERIC_DB_SETUP_FAILED,
105 : NULL);
106 0 : return GNUNET_SYSERR;
107 : }
108 0 : GNUNET_assert (mt < TEH_MT_REQUEST_COUNT);
109 0 : TEH_METRICS_num_requests[mt]++;
110 0 : for (unsigned int retries = 0;
111 : retries < MAX_TRANSACTION_COMMIT_RETRIES;
112 0 : retries++)
113 : {
114 : enum GNUNET_DB_QueryStatus qs;
115 :
116 0 : if (GNUNET_OK !=
117 0 : TEH_plugin->start (TEH_plugin->cls,
118 : name))
119 : {
120 0 : GNUNET_break (0);
121 0 : if (NULL != mhd_ret)
122 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
123 : MHD_HTTP_INTERNAL_SERVER_ERROR,
124 : TALER_EC_GENERIC_DB_START_FAILED,
125 : NULL);
126 0 : return GNUNET_SYSERR;
127 : }
128 0 : qs = cb (cb_cls,
129 : connection,
130 : mhd_ret);
131 0 : if (0 > qs)
132 : {
133 0 : TEH_plugin->rollback (TEH_plugin->cls);
134 0 : if (GNUNET_DB_STATUS_HARD_ERROR == qs)
135 0 : return GNUNET_SYSERR;
136 : }
137 : else
138 : {
139 0 : qs = TEH_plugin->commit (TEH_plugin->cls);
140 0 : if (GNUNET_DB_STATUS_HARD_ERROR == qs)
141 : {
142 0 : TEH_plugin->rollback (TEH_plugin->cls);
143 0 : if (NULL != mhd_ret)
144 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
145 : MHD_HTTP_INTERNAL_SERVER_ERROR,
146 : TALER_EC_GENERIC_DB_COMMIT_FAILED,
147 : NULL);
148 0 : return GNUNET_SYSERR;
149 : }
150 0 : if (0 > qs)
151 0 : TEH_plugin->rollback (TEH_plugin->cls);
152 : }
153 : /* make sure callback did not violate invariants! */
154 0 : GNUNET_assert ( (NULL == mhd_ret) ||
155 : (-1 == (int) *mhd_ret) );
156 0 : if (0 <= qs)
157 0 : return GNUNET_OK;
158 0 : TEH_METRICS_num_conflict[mt]++;
159 : }
160 0 : TEH_plugin->rollback (TEH_plugin->cls);
161 0 : TALER_LOG_ERROR ("Transaction `%s' commit failed %u times\n",
162 : name,
163 : MAX_TRANSACTION_COMMIT_RETRIES);
164 0 : if (NULL != mhd_ret)
165 0 : *mhd_ret = TALER_MHD_reply_with_error (connection,
166 : MHD_HTTP_INTERNAL_SERVER_ERROR,
167 : TALER_EC_GENERIC_DB_SOFT_FAILURE,
168 : NULL);
169 0 : return GNUNET_SYSERR;
170 : }
171 :
172 :
173 : /* end of taler-exchange-httpd_db.c */
|