exchange_api_post-management-wire-fee.c (8068B)
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-wire-fee.c 19 * @brief functions to set wire 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-wire-fee.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_PostManagementWireFeesHandle 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_PostManagementWireFeesCallback cb; 60 61 /** 62 * Closure for @a cb. 63 */ 64 TALER_EXCHANGE_POST_MANAGEMENT_WIRE_FEES_RESULT_CLOSURE *cb_cls; 65 66 /** 67 * Reference to the execution context. 68 */ 69 struct GNUNET_CURL_Context *ctx; 70 71 /** 72 * Wire method these fees are for. 73 */ 74 char *wire_method; 75 76 /** 77 * Start of validity period. 78 */ 79 struct GNUNET_TIME_Timestamp validity_start; 80 81 /** 82 * End of validity period. 83 */ 84 struct GNUNET_TIME_Timestamp validity_end; 85 86 /** 87 * Wire fees for this time period. 88 */ 89 struct TALER_WireFeeSet fees; 90 91 /** 92 * Signature affirming the wire fees. 93 */ 94 struct TALER_MasterSignatureP master_sig; 95 96 }; 97 98 99 /** 100 * Function called when we're done processing the 101 * HTTP POST /management/wire-fees request. 102 * 103 * @param cls the `struct TALER_EXCHANGE_PostManagementWireFeesHandle` 104 * @param response_code HTTP response code, 0 on error 105 * @param response response body, NULL if not in JSON 106 */ 107 static void 108 handle_wire_fees_finished (void *cls, 109 long response_code, 110 const void *response) 111 { 112 struct TALER_EXCHANGE_PostManagementWireFeesHandle *pmwfh = cls; 113 const json_t *json = response; 114 struct TALER_EXCHANGE_PostManagementWireFeesResponse res = { 115 .hr.http_status = (unsigned int) response_code, 116 .hr.reply = json 117 }; 118 119 pmwfh->job = NULL; 120 switch (response_code) 121 { 122 case MHD_HTTP_NO_CONTENT: 123 break; 124 case MHD_HTTP_FORBIDDEN: 125 res.hr.ec = TALER_JSON_get_error_code (json); 126 res.hr.hint = TALER_JSON_get_error_hint (json); 127 break; 128 case MHD_HTTP_NOT_FOUND: 129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 130 "Server did not find handler at `%s'. Did you configure the correct exchange base URL?\n", 131 pmwfh->url); 132 if (NULL != json) 133 { 134 res.hr.ec = TALER_JSON_get_error_code (json); 135 res.hr.hint = TALER_JSON_get_error_hint (json); 136 } 137 else 138 { 139 res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 140 res.hr.hint = TALER_ErrorCode_get_hint (res.hr.ec); 141 } 142 break; 143 case MHD_HTTP_CONFLICT: 144 res.hr.ec = TALER_JSON_get_error_code (json); 145 res.hr.hint = TALER_JSON_get_error_hint (json); 146 break; 147 case MHD_HTTP_PRECONDITION_FAILED: 148 res.hr.ec = TALER_JSON_get_error_code (json); 149 res.hr.hint = TALER_JSON_get_error_hint (json); 150 break; 151 default: 152 /* unexpected response code */ 153 GNUNET_break_op (0); 154 res.hr.ec = TALER_JSON_get_error_code (json); 155 res.hr.hint = TALER_JSON_get_error_hint (json); 156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 157 "Unexpected response code %u/%d for exchange management set wire fee\n", 158 (unsigned int) response_code, 159 (int) res.hr.ec); 160 break; 161 } 162 if (NULL != pmwfh->cb) 163 { 164 pmwfh->cb (pmwfh->cb_cls, 165 &res); 166 pmwfh->cb = NULL; 167 } 168 TALER_EXCHANGE_post_management_wire_fees_cancel (pmwfh); 169 } 170 171 172 struct TALER_EXCHANGE_PostManagementWireFeesHandle * 173 TALER_EXCHANGE_post_management_wire_fees_create ( 174 struct GNUNET_CURL_Context *ctx, 175 const char *exchange_base_url, 176 const char *wire_method, 177 struct GNUNET_TIME_Timestamp validity_start, 178 struct GNUNET_TIME_Timestamp validity_end, 179 const struct TALER_WireFeeSet *fees, 180 const struct TALER_MasterSignatureP *master_sig) 181 { 182 struct TALER_EXCHANGE_PostManagementWireFeesHandle *pmwfh; 183 184 pmwfh = GNUNET_new (struct TALER_EXCHANGE_PostManagementWireFeesHandle); 185 pmwfh->ctx = ctx; 186 pmwfh->base_url = GNUNET_strdup (exchange_base_url); 187 pmwfh->wire_method = GNUNET_strdup (wire_method); 188 pmwfh->validity_start = validity_start; 189 pmwfh->validity_end = validity_end; 190 pmwfh->fees = *fees; 191 pmwfh->master_sig = *master_sig; 192 return pmwfh; 193 } 194 195 196 enum TALER_ErrorCode 197 TALER_EXCHANGE_post_management_wire_fees_start ( 198 struct TALER_EXCHANGE_PostManagementWireFeesHandle *pmwfh, 199 TALER_EXCHANGE_PostManagementWireFeesCallback cb, 200 TALER_EXCHANGE_POST_MANAGEMENT_WIRE_FEES_RESULT_CLOSURE *cb_cls) 201 { 202 CURL *eh; 203 json_t *body; 204 205 pmwfh->cb = cb; 206 pmwfh->cb_cls = cb_cls; 207 pmwfh->url = TALER_url_join (pmwfh->base_url, 208 "management/wire-fee", 209 NULL); 210 if (NULL == pmwfh->url) 211 { 212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 213 "Could not construct request URL.\n"); 214 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 215 } 216 body = GNUNET_JSON_PACK ( 217 GNUNET_JSON_pack_string ("wire_method", 218 pmwfh->wire_method), 219 GNUNET_JSON_pack_data_auto ("master_sig", 220 &pmwfh->master_sig), 221 GNUNET_JSON_pack_timestamp ("fee_start", 222 pmwfh->validity_start), 223 GNUNET_JSON_pack_timestamp ("fee_end", 224 pmwfh->validity_end), 225 TALER_JSON_pack_amount ("closing_fee", 226 &pmwfh->fees.closing), 227 TALER_JSON_pack_amount ("wire_fee", 228 &pmwfh->fees.wire)); 229 eh = TALER_EXCHANGE_curl_easy_get_ (pmwfh->url); 230 if ( (NULL == eh) || 231 (GNUNET_OK != 232 TALER_curl_easy_post (&pmwfh->post_ctx, 233 eh, 234 body)) ) 235 { 236 GNUNET_break (0); 237 if (NULL != eh) 238 curl_easy_cleanup (eh); 239 json_decref (body); 240 GNUNET_free (pmwfh->url); 241 pmwfh->url = NULL; 242 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 243 } 244 json_decref (body); 245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 246 "Requesting URL '%s'\n", 247 pmwfh->url); 248 pmwfh->job = GNUNET_CURL_job_add2 (pmwfh->ctx, 249 eh, 250 pmwfh->post_ctx.headers, 251 &handle_wire_fees_finished, 252 pmwfh); 253 if (NULL == pmwfh->job) 254 { 255 TALER_curl_easy_post_finished (&pmwfh->post_ctx); 256 GNUNET_free (pmwfh->url); 257 pmwfh->url = NULL; 258 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 259 } 260 return TALER_EC_NONE; 261 } 262 263 264 void 265 TALER_EXCHANGE_post_management_wire_fees_cancel ( 266 struct TALER_EXCHANGE_PostManagementWireFeesHandle *pmwfh) 267 { 268 if (NULL != pmwfh->job) 269 { 270 GNUNET_CURL_job_cancel (pmwfh->job); 271 pmwfh->job = NULL; 272 } 273 TALER_curl_easy_post_finished (&pmwfh->post_ctx); 274 GNUNET_free (pmwfh->wire_method); 275 GNUNET_free (pmwfh->url); 276 GNUNET_free (pmwfh->base_url); 277 GNUNET_free (pmwfh); 278 } 279 280 281 /* end of exchange_api_post-management-wire-fee.c */