exchange_api_post-management-drain.c (7702B)
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-drain.c 19 * @brief functions to drain profits from an exchange account 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-drain.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_PostManagementDrainHandle 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_PostManagementDrainCallback cb; 60 61 /** 62 * Closure for @a cb. 63 */ 64 TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls; 65 66 /** 67 * Reference to the execution context. 68 */ 69 struct GNUNET_CURL_Context *ctx; 70 71 /** 72 * Wire transfer identifier to use. 73 */ 74 struct TALER_WireTransferIdentifierRawP wtid; 75 76 /** 77 * Total to transfer. 78 */ 79 struct TALER_Amount amount; 80 81 /** 82 * When was the request created. 83 */ 84 struct GNUNET_TIME_Timestamp date; 85 86 /** 87 * Configuration section identifying account to debit. 88 */ 89 char *account_section; 90 91 /** 92 * Payto URI of the account to credit. 93 */ 94 char *payto_uri_str; 95 96 /** 97 * Signature affirming the operation. 98 */ 99 struct TALER_MasterSignatureP master_sig; 100 101 }; 102 103 104 /** 105 * Function called when we're done processing the 106 * HTTP POST /management/drain request. 107 * 108 * @param cls the `struct TALER_EXCHANGE_PostManagementDrainHandle` 109 * @param response_code HTTP response code, 0 on error 110 * @param response response body, NULL if not in JSON 111 */ 112 static void 113 handle_drain_finished (void *cls, 114 long response_code, 115 const void *response) 116 { 117 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh = cls; 118 const json_t *json = response; 119 struct TALER_EXCHANGE_PostManagementDrainResponse res = { 120 .hr.http_status = (unsigned int) response_code, 121 .hr.reply = json 122 }; 123 124 pmdh->job = NULL; 125 switch (response_code) 126 { 127 case MHD_HTTP_NO_CONTENT: 128 break; 129 case MHD_HTTP_FORBIDDEN: 130 res.hr.ec = TALER_JSON_get_error_code (json); 131 res.hr.hint = TALER_JSON_get_error_hint (json); 132 break; 133 case MHD_HTTP_CONFLICT: 134 res.hr.ec = TALER_JSON_get_error_code (json); 135 res.hr.hint = TALER_JSON_get_error_hint (json); 136 break; 137 case MHD_HTTP_PRECONDITION_FAILED: 138 res.hr.ec = TALER_JSON_get_error_code (json); 139 res.hr.hint = TALER_JSON_get_error_hint (json); 140 break; 141 default: 142 /* unexpected response code */ 143 GNUNET_break_op (0); 144 res.hr.ec = TALER_JSON_get_error_code (json); 145 res.hr.hint = TALER_JSON_get_error_hint (json); 146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 147 "Unexpected response code %u/%d for exchange management drain profits\n", 148 (unsigned int) response_code, 149 (int) res.hr.ec); 150 break; 151 } 152 if (NULL != pmdh->cb) 153 { 154 pmdh->cb (pmdh->cb_cls, 155 &res); 156 pmdh->cb = NULL; 157 } 158 TALER_EXCHANGE_post_management_drain_cancel (pmdh); 159 } 160 161 162 struct TALER_EXCHANGE_PostManagementDrainHandle * 163 TALER_EXCHANGE_post_management_drain_create ( 164 struct GNUNET_CURL_Context *ctx, 165 const char *url, 166 const struct TALER_WireTransferIdentifierRawP *wtid, 167 const struct TALER_Amount *amount, 168 struct GNUNET_TIME_Timestamp date, 169 const char *account_section, 170 const struct TALER_FullPayto payto_uri, 171 const struct TALER_MasterSignatureP *master_sig) 172 { 173 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh; 174 175 pmdh = GNUNET_new (struct TALER_EXCHANGE_PostManagementDrainHandle); 176 pmdh->ctx = ctx; 177 pmdh->base_url = GNUNET_strdup (url); 178 pmdh->wtid = *wtid; 179 pmdh->amount = *amount; 180 pmdh->date = date; 181 pmdh->account_section = GNUNET_strdup (account_section); 182 pmdh->payto_uri_str = GNUNET_strdup (payto_uri.full_payto); 183 pmdh->master_sig = *master_sig; 184 return pmdh; 185 } 186 187 188 enum TALER_ErrorCode 189 TALER_EXCHANGE_post_management_drain_start ( 190 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh, 191 TALER_EXCHANGE_PostManagementDrainCallback cb, 192 TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls) 193 { 194 CURL *eh; 195 json_t *body; 196 struct TALER_FullPayto payto_uri = { 197 .full_payto = pmdh->payto_uri_str 198 }; 199 200 pmdh->cb = cb; 201 pmdh->cb_cls = cb_cls; 202 pmdh->url = TALER_url_join (pmdh->base_url, 203 "management/drain", 204 NULL); 205 if (NULL == pmdh->url) 206 { 207 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 208 "Could not construct request URL.\n"); 209 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 210 } 211 body = GNUNET_JSON_PACK ( 212 GNUNET_JSON_pack_string ("debit_account_section", 213 pmdh->account_section), 214 TALER_JSON_pack_full_payto ("credit_payto_uri", 215 payto_uri), 216 GNUNET_JSON_pack_data_auto ("wtid", 217 &pmdh->wtid), 218 GNUNET_JSON_pack_data_auto ("master_sig", 219 &pmdh->master_sig), 220 GNUNET_JSON_pack_timestamp ("date", 221 pmdh->date), 222 TALER_JSON_pack_amount ("amount", 223 &pmdh->amount)); 224 eh = TALER_EXCHANGE_curl_easy_get_ (pmdh->url); 225 if ( (NULL == eh) || 226 (GNUNET_OK != 227 TALER_curl_easy_post (&pmdh->post_ctx, 228 eh, 229 body)) ) 230 { 231 GNUNET_break (0); 232 if (NULL != eh) 233 curl_easy_cleanup (eh); 234 json_decref (body); 235 GNUNET_free (pmdh->url); 236 pmdh->url = NULL; 237 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 238 } 239 json_decref (body); 240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 241 "Requesting URL '%s'\n", 242 pmdh->url); 243 pmdh->job = GNUNET_CURL_job_add2 (pmdh->ctx, 244 eh, 245 pmdh->post_ctx.headers, 246 &handle_drain_finished, 247 pmdh); 248 if (NULL == pmdh->job) 249 { 250 TALER_curl_easy_post_finished (&pmdh->post_ctx); 251 GNUNET_free (pmdh->url); 252 pmdh->url = NULL; 253 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 254 } 255 return TALER_EC_NONE; 256 } 257 258 259 void 260 TALER_EXCHANGE_post_management_drain_cancel ( 261 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh) 262 { 263 if (NULL != pmdh->job) 264 { 265 GNUNET_CURL_job_cancel (pmdh->job); 266 pmdh->job = NULL; 267 } 268 TALER_curl_easy_post_finished (&pmdh->post_ctx); 269 GNUNET_free (pmdh->account_section); 270 GNUNET_free (pmdh->payto_uri_str); 271 GNUNET_free (pmdh->url); 272 GNUNET_free (pmdh->base_url); 273 GNUNET_free (pmdh); 274 } 275 276 277 /* end of exchange_api_post-management-drain.c */