exchange_api_post-management-global-fees.c (8852B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2026 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 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file lib/exchange_api_post-management-global-fees.c 19 * @brief functions to set global fees at an exchange 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include "taler/taler_json_lib.h" 24 #include <gnunet/gnunet_curl_lib.h> 25 #include <microhttpd.h> 26 #include "taler/taler_exchange_service.h" 27 #include "taler/taler-exchange/post-management-global-fees.h" 28 #include "exchange_api_curl_defaults.h" 29 #include "taler/taler_signatures.h" 30 #include "taler/taler_curl_lib.h" 31 32 33 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle 34 { 35 36 /** 37 * The base URL for this request. 38 */ 39 char *base_url; 40 41 /** 42 * The full URL for this request, set during _start. 43 */ 44 char *url; 45 46 /** 47 * Minor context that holds body and headers. 48 */ 49 struct TALER_CURL_PostContext post_ctx; 50 51 /** 52 * Handle for the request. 53 */ 54 struct GNUNET_CURL_Job *job; 55 56 /** 57 * Function to call with the result. 58 */ 59 TALER_EXCHANGE_PostManagementGlobalFeesCallback cb; 60 61 /** 62 * Closure for @a cb. 63 */ 64 TALER_EXCHANGE_POST_MANAGEMENT_GLOBAL_FEES_RESULT_CLOSURE *cb_cls; 65 66 /** 67 * Reference to the execution context. 68 */ 69 struct GNUNET_CURL_Context *ctx; 70 71 /** 72 * Start of validity period. 73 */ 74 struct GNUNET_TIME_Timestamp validity_start; 75 76 /** 77 * End of validity period. 78 */ 79 struct GNUNET_TIME_Timestamp validity_end; 80 81 /** 82 * Global fees for this time period. 83 */ 84 struct TALER_GlobalFeeSet fees; 85 86 /** 87 * When do purses time out. 88 */ 89 struct GNUNET_TIME_Relative purse_timeout; 90 91 /** 92 * How long are account histories preserved. 93 */ 94 struct GNUNET_TIME_Relative history_expiration; 95 96 /** 97 * How many purses are free per account. 98 */ 99 uint32_t purse_account_limit; 100 101 /** 102 * Signature affirming the global fees. 103 */ 104 struct TALER_MasterSignatureP master_sig; 105 106 }; 107 108 109 /** 110 * Function called when we're done processing the 111 * HTTP POST /management/global-fees request. 112 * 113 * @param cls the `struct TALER_EXCHANGE_PostManagementGlobalFeesHandle` 114 * @param response_code HTTP response code, 0 on error 115 * @param response response body, NULL if not in JSON 116 */ 117 static void 118 handle_global_fees_finished (void *cls, 119 long response_code, 120 const void *response) 121 { 122 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle *pmgfh = cls; 123 const json_t *json = response; 124 struct TALER_EXCHANGE_PostManagementGlobalFeesResponse res = { 125 .hr.http_status = (unsigned int) response_code, 126 .hr.reply = json 127 }; 128 129 pmgfh->job = NULL; 130 switch (response_code) 131 { 132 case MHD_HTTP_NO_CONTENT: 133 break; 134 case MHD_HTTP_FORBIDDEN: 135 res.hr.ec = TALER_JSON_get_error_code (json); 136 res.hr.hint = TALER_JSON_get_error_hint (json); 137 break; 138 case MHD_HTTP_NOT_FOUND: 139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 140 "Server did not find handler at `%s'. Did you configure the correct exchange base URL?\n", 141 pmgfh->url); 142 if (NULL != json) 143 { 144 res.hr.ec = TALER_JSON_get_error_code (json); 145 res.hr.hint = TALER_JSON_get_error_hint (json); 146 } 147 else 148 { 149 res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 150 res.hr.hint = TALER_ErrorCode_get_hint (res.hr.ec); 151 } 152 break; 153 case MHD_HTTP_CONFLICT: 154 res.hr.ec = TALER_JSON_get_error_code (json); 155 res.hr.hint = TALER_JSON_get_error_hint (json); 156 break; 157 case MHD_HTTP_PRECONDITION_FAILED: 158 res.hr.ec = TALER_JSON_get_error_code (json); 159 res.hr.hint = TALER_JSON_get_error_hint (json); 160 break; 161 default: 162 /* unexpected response code */ 163 GNUNET_break_op (0); 164 res.hr.ec = TALER_JSON_get_error_code (json); 165 res.hr.hint = TALER_JSON_get_error_hint (json); 166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 167 "Unexpected response code %u/%d for exchange management set global fee\n", 168 (unsigned int) response_code, 169 (int) res.hr.ec); 170 break; 171 } 172 if (NULL != pmgfh->cb) 173 { 174 pmgfh->cb (pmgfh->cb_cls, 175 &res); 176 pmgfh->cb = NULL; 177 } 178 TALER_EXCHANGE_post_management_global_fees_cancel (pmgfh); 179 } 180 181 182 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle * 183 TALER_EXCHANGE_post_management_global_fees_create ( 184 struct GNUNET_CURL_Context *ctx, 185 const char *exchange_base_url, 186 struct GNUNET_TIME_Timestamp validity_start, 187 struct GNUNET_TIME_Timestamp validity_end, 188 const struct TALER_GlobalFeeSet *fees, 189 struct GNUNET_TIME_Relative purse_timeout, 190 struct GNUNET_TIME_Relative history_expiration, 191 uint32_t purse_account_limit, 192 const struct TALER_MasterSignatureP *master_sig) 193 { 194 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle *pmgfh; 195 196 pmgfh = GNUNET_new (struct TALER_EXCHANGE_PostManagementGlobalFeesHandle); 197 pmgfh->ctx = ctx; 198 pmgfh->base_url = GNUNET_strdup (exchange_base_url); 199 pmgfh->validity_start = validity_start; 200 pmgfh->validity_end = validity_end; 201 pmgfh->fees = *fees; 202 pmgfh->purse_timeout = purse_timeout; 203 pmgfh->history_expiration = history_expiration; 204 pmgfh->purse_account_limit = purse_account_limit; 205 pmgfh->master_sig = *master_sig; 206 return pmgfh; 207 } 208 209 210 enum TALER_ErrorCode 211 TALER_EXCHANGE_post_management_global_fees_start ( 212 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle *pmgfh, 213 TALER_EXCHANGE_PostManagementGlobalFeesCallback cb, 214 TALER_EXCHANGE_POST_MANAGEMENT_GLOBAL_FEES_RESULT_CLOSURE *cb_cls) 215 { 216 CURL *eh; 217 json_t *body; 218 219 pmgfh->cb = cb; 220 pmgfh->cb_cls = cb_cls; 221 pmgfh->url = TALER_url_join (pmgfh->base_url, 222 "management/global-fee", 223 NULL); 224 if (NULL == pmgfh->url) 225 { 226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 227 "Could not construct request URL.\n"); 228 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 229 } 230 body = GNUNET_JSON_PACK ( 231 GNUNET_JSON_pack_data_auto ("master_sig", 232 &pmgfh->master_sig), 233 GNUNET_JSON_pack_timestamp ("fee_start", 234 pmgfh->validity_start), 235 GNUNET_JSON_pack_timestamp ("fee_end", 236 pmgfh->validity_end), 237 TALER_JSON_pack_amount ("history_fee", 238 &pmgfh->fees.history), 239 TALER_JSON_pack_amount ("account_fee", 240 &pmgfh->fees.account), 241 TALER_JSON_pack_amount ("purse_fee", 242 &pmgfh->fees.purse), 243 GNUNET_JSON_pack_time_rel ("purse_timeout", 244 pmgfh->purse_timeout), 245 GNUNET_JSON_pack_time_rel ("history_expiration", 246 pmgfh->history_expiration), 247 GNUNET_JSON_pack_uint64 ("purse_account_limit", 248 pmgfh->purse_account_limit)); 249 eh = TALER_EXCHANGE_curl_easy_get_ (pmgfh->url); 250 if ( (NULL == eh) || 251 (GNUNET_OK != 252 TALER_curl_easy_post (&pmgfh->post_ctx, 253 eh, 254 body)) ) 255 { 256 GNUNET_break (0); 257 if (NULL != eh) 258 curl_easy_cleanup (eh); 259 json_decref (body); 260 GNUNET_free (pmgfh->url); 261 pmgfh->url = NULL; 262 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 263 } 264 json_decref (body); 265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 266 "Requesting URL '%s'\n", 267 pmgfh->url); 268 pmgfh->job = GNUNET_CURL_job_add2 (pmgfh->ctx, 269 eh, 270 pmgfh->post_ctx.headers, 271 &handle_global_fees_finished, 272 pmgfh); 273 if (NULL == pmgfh->job) 274 { 275 GNUNET_break (0); 276 TALER_curl_easy_post_finished (&pmgfh->post_ctx); 277 GNUNET_free (pmgfh->url); 278 pmgfh->url = NULL; 279 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 280 } 281 return TALER_EC_NONE; 282 } 283 284 285 void 286 TALER_EXCHANGE_post_management_global_fees_cancel ( 287 struct TALER_EXCHANGE_PostManagementGlobalFeesHandle *pmgfh) 288 { 289 if (NULL != pmgfh->job) 290 { 291 GNUNET_CURL_job_cancel (pmgfh->job); 292 pmgfh->job = NULL; 293 } 294 TALER_curl_easy_post_finished (&pmgfh->post_ctx); 295 GNUNET_free (pmgfh->url); 296 GNUNET_free (pmgfh->base_url); 297 GNUNET_free (pmgfh); 298 } 299 300 301 /* end of exchange_api_post-management-global-fees.c */