work on #5077: reserve_pub vs. wtid issue, add reject functionality to wire plugin API (with stub implementations for now)
This commit is contained in:
parent
f299130c50
commit
8440de1333
@ -70,7 +70,8 @@ static struct GNUNET_CONTAINER_MultiHashMap *in_map;
|
||||
|
||||
/**
|
||||
* Map with information about outgoing wire transfers.
|
||||
* Maps hashes of the wire offsets to `struct ReserveOutInfo`s.
|
||||
* Maps hashes of the wire subjects (in binary encoding)
|
||||
* to `struct ReserveOutInfo`s.
|
||||
*/
|
||||
static struct GNUNET_CONTAINER_MultiHashMap *out_map;
|
||||
|
||||
@ -658,7 +659,9 @@ complain_out_not_found (void *cls,
|
||||
"row", (json_int_t) 0,
|
||||
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
||||
"amount_justified", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&roi->details.reserve_pub), /* #5077 missnomer */
|
||||
"wtid", (NULL == roi->details.wtid_s)
|
||||
? GNUNET_JSON_from_data_auto (&roi->details.wtid)
|
||||
: json_string (roi->details.wtid_s),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (roi->details.execution_date),
|
||||
"diagnostic", "justification for wire transfer not found"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
@ -726,6 +729,7 @@ history_debit_cb (void *cls,
|
||||
const struct TALER_WIRE_TransferDetails *details)
|
||||
{
|
||||
struct ReserveOutInfo *roi;
|
||||
struct GNUNET_HashCode rowh;
|
||||
|
||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||
{
|
||||
@ -735,13 +739,36 @@ history_debit_cb (void *cls,
|
||||
check_exchange_wire_out ();
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (NULL != details->wtid_s)
|
||||
{
|
||||
char *diagnostic;
|
||||
|
||||
GNUNET_CRYPTO_hash (row_off,
|
||||
row_off_size,
|
||||
&rowh);
|
||||
GNUNET_asprintf (&diagnostic,
|
||||
"malformed wire transfer subject `%s'",
|
||||
details->wtid_s);
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:o, s:o, s:s}",
|
||||
"table", "bank wire log",
|
||||
"row", (json_int_t) 0,
|
||||
"amount", TALER_JSON_from_amount (&details->amount),
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&rowh),
|
||||
"diagnostic", diagnostic));
|
||||
/* TODO: report generator currently ignores 'amount' for this
|
||||
table, maybe use a different table to report this issue! */
|
||||
/* TODO: add 'amount' to some total amount that was badly wired! */
|
||||
GNUNET_free (diagnostic);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
roi = GNUNET_new (struct ReserveOutInfo);
|
||||
GNUNET_CRYPTO_hash (&details->reserve_pub, /* FIXME (#5077): missnomer */
|
||||
sizeof (details->reserve_pub),
|
||||
GNUNET_CRYPTO_hash (&details->wtid,
|
||||
sizeof (details->wtid),
|
||||
&roi->subject_hash);
|
||||
roi->details.amount = details->amount;
|
||||
roi->details.execution_date = details->execution_date;
|
||||
roi->details.reserve_pub = details->reserve_pub; /* FIXME (#5077): missnomer & redundant */
|
||||
roi->details.wtid = details->wtid;
|
||||
roi->details.account_details = json_incref ((json_t *) details->account_details);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONTAINER_multihashmap_put (out_map,
|
||||
@ -749,13 +776,25 @@ history_debit_cb (void *cls,
|
||||
roi,
|
||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
||||
{
|
||||
GNUNET_break_op (0); /* duplicate wire offset is not allowed! */
|
||||
char *diagnostic;
|
||||
|
||||
GNUNET_CRYPTO_hash (row_off,
|
||||
row_off_size,
|
||||
&rowh);
|
||||
GNUNET_asprintf (&diagnostic,
|
||||
"duplicate wire transfer subject `%s'",
|
||||
TALER_B2S (&roi->subject_hash));
|
||||
report (report_row_inconsistencies,
|
||||
json_pack ("{s:s, s:I, s:o, s:s}",
|
||||
json_pack ("{s:s, s:I, s:o, s:o, s:s}",
|
||||
"table", "bank wire log",
|
||||
"row", (json_int_t) 0,
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&roi->subject_hash),
|
||||
"diagnostic", "duplicate wire offset"));
|
||||
"amount", TALER_JSON_from_amount (&details->amount),
|
||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&rowh),
|
||||
"diagnostic", diagnostic));
|
||||
/* TODO: report generator currently ignores 'amount' for this
|
||||
table, maybe use a different table to report this issue! */
|
||||
/* TODO: add 'amount' to some total amount that was badly wired! */
|
||||
GNUNET_free (diagnostic);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
@ -830,7 +869,12 @@ reserve_in_cb (void *cls,
|
||||
rii->row_off_size = wire_reference_size;
|
||||
rii->details.amount = *credit;
|
||||
rii->details.execution_date = execution_date;
|
||||
rii->details.reserve_pub = *reserve_pub;
|
||||
/* reserve public key should be the WTID */
|
||||
GNUNET_assert (sizeof (rii->details.wtid) ==
|
||||
sizeof (*reserve_pub));
|
||||
memcpy (&rii->details.wtid,
|
||||
reserve_pub,
|
||||
sizeof (*reserve_pub));
|
||||
rii->details.account_details = json_incref ((json_t *) sender_account_details);
|
||||
rii->rowid = rowid;
|
||||
if (GNUNET_OK !=
|
||||
@ -875,7 +919,7 @@ complain_in_not_found (void *cls,
|
||||
"row", (json_int_t) rii->rowid,
|
||||
"amount_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub), /* also reserve_pub, but see #5077 missnomer */
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||
"diagnostic", "incoming wire transfer claimed by exchange not found"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
@ -966,16 +1010,16 @@ history_credit_cb (void *cls,
|
||||
"diagnostic", "wire reference size missmatch"));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (0 != memcmp (&details->reserve_pub,
|
||||
&rii->details.reserve_pub,
|
||||
sizeof (struct TALER_ReservePublicKeyP)))
|
||||
if (0 != memcmp (&details->wtid,
|
||||
&rii->details.wtid,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP)))
|
||||
{
|
||||
report (report_reserve_in_inconsistencies,
|
||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub), /* #5077 missnomer */
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||
"diagnostic", "wire subject does not match"));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
@ -987,7 +1031,7 @@ history_credit_cb (void *cls,
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&zero),
|
||||
"amount_wired", TALER_JSON_from_amount (&details->amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->reserve_pub), /* #5077 missnomer */
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||
"diagnostic", "wire subject does not match"));
|
||||
|
||||
@ -1005,7 +1049,7 @@ history_credit_cb (void *cls,
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"amount_wired", TALER_JSON_from_amount (&details->amount),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->reserve_pub), /* #5077 missnomer */
|
||||
"wtid", GNUNET_JSON_from_data_auto (&details->wtid),
|
||||
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||
"diagnostic", "wire amount does not match"));
|
||||
if (0 < TALER_amount_cmp (&details->amount,
|
||||
@ -1046,7 +1090,7 @@ history_credit_cb (void *cls,
|
||||
json_pack ("{s:s, s:o, s:o}",
|
||||
"amount", TALER_JSON_from_amount (&rii->details.amount),
|
||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.reserve_pub))); /* FIXME #5077 missnomer */
|
||||
"wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid)));
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
TALER_amount_add (&total_missattribution_in,
|
||||
&total_missattribution_in,
|
||||
|
@ -36,6 +36,23 @@
|
||||
#define DELAY GNUNET_TIME_UNIT_SECONDS
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #reject_cb().
|
||||
*/
|
||||
struct RejectContext
|
||||
{
|
||||
/**
|
||||
* Wire transfer subject that was illformed.
|
||||
*/
|
||||
char *wtid_s;
|
||||
|
||||
/**
|
||||
* Database session that encountered the problem.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_Session *session;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle to the plugin.
|
||||
*/
|
||||
@ -109,6 +126,11 @@ static struct GNUNET_SCHEDULER_Task *task;
|
||||
*/
|
||||
static struct TALER_WIRE_HistoryHandle *hh;
|
||||
|
||||
/**
|
||||
* Active request to reject a wire transfer.
|
||||
*/
|
||||
static struct TALER_WIRE_RejectHandle *rt;
|
||||
|
||||
|
||||
/**
|
||||
* We're being aborted with CTRL-C (or SIGTERM). Shut down.
|
||||
@ -129,6 +151,15 @@ shutdown_task (void *cls)
|
||||
hh);
|
||||
hh = NULL;
|
||||
}
|
||||
if (NULL != rt)
|
||||
{
|
||||
char *wtid_s;
|
||||
|
||||
wtid_s = wire_plugin->reject_transfer_cancel (wire_plugin->cls,
|
||||
rt);
|
||||
rt = NULL;
|
||||
GNUNET_free (wtid_s);
|
||||
}
|
||||
TALER_EXCHANGEDB_plugin_unload (db_plugin);
|
||||
db_plugin = NULL;
|
||||
TALER_WIRE_plugin_unload (wire_plugin);
|
||||
@ -204,6 +235,48 @@ static void
|
||||
find_transfers (void *cls);
|
||||
|
||||
|
||||
/**
|
||||
* Function called upon completion of the rejection of a wire transfer.
|
||||
*
|
||||
* @param cls closure with the `struct RejectContext`
|
||||
* @param ec error code for the operation
|
||||
*/
|
||||
static void
|
||||
reject_cb (void *cls,
|
||||
enum TALER_ErrorCode ec)
|
||||
{
|
||||
struct RejectContext *rtc = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
rt = NULL;
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to wire back transfer `%s': %d\n",
|
||||
rtc->wtid_s,
|
||||
ec);
|
||||
GNUNET_free (rtc->wtid_s);
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
rtc->session);
|
||||
GNUNET_free (rtc);
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return;
|
||||
}
|
||||
GNUNET_free (rtc->wtid_s);
|
||||
qs = db_plugin->commit (db_plugin->cls,
|
||||
rtc->session);
|
||||
GNUNET_free (rtc);
|
||||
if (0 <= qs)
|
||||
{
|
||||
GNUNET_free_non_null (start_off);
|
||||
start_off = last_row_off;
|
||||
start_off_size = last_row_off_size;
|
||||
}
|
||||
task = GNUNET_SCHEDULER_add_now (&find_transfers,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank for the transaction history.
|
||||
@ -224,6 +297,7 @@ history_cb (void *cls,
|
||||
{
|
||||
struct TALER_EXCHANGEDB_Session *session = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
|
||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||
{
|
||||
@ -254,13 +328,45 @@ history_cb (void *cls,
|
||||
NULL);
|
||||
return GNUNET_OK; /* will be ignored anyway */
|
||||
}
|
||||
if (NULL != details->wtid_s)
|
||||
{
|
||||
struct RejectContext *rtc;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Wire transfer over %s has invalid subject `%s', sending it back!\n",
|
||||
TALER_amount2s (&details->amount),
|
||||
details->wtid_s);
|
||||
if (last_row_off_size != row_off_size)
|
||||
{
|
||||
GNUNET_free_non_null (last_row_off);
|
||||
last_row_off = GNUNET_malloc (row_off_size);
|
||||
}
|
||||
memcpy (last_row_off,
|
||||
row_off,
|
||||
row_off_size);
|
||||
rtc = GNUNET_new (struct RejectContext);
|
||||
rtc->session = session;
|
||||
rtc->wtid_s = GNUNET_strdup (details->wtid_s);
|
||||
rt = wire_plugin->reject_transfer (wire_plugin->cls,
|
||||
row_off,
|
||||
row_off_size,
|
||||
&reject_cb,
|
||||
rtc);
|
||||
return GNUNET_SYSERR; /* will continue later... */
|
||||
}
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Adding wire transfer over %s with subject `%s'\n",
|
||||
TALER_amount2s (&details->amount),
|
||||
TALER_B2S (&details->reserve_pub));
|
||||
TALER_B2S (&details->wtid));
|
||||
/* Wire transfer identifier == reserve public key */
|
||||
GNUNET_assert (sizeof (reserve_pub) == sizeof (details->wtid));
|
||||
memcpy (&reserve_pub,
|
||||
&details->wtid,
|
||||
sizeof (reserve_pub));
|
||||
qs = db_plugin->reserves_in_insert (db_plugin->cls,
|
||||
session,
|
||||
&details->reserve_pub,
|
||||
&reserve_pub,
|
||||
&details->amount,
|
||||
details->execution_date,
|
||||
details->account_details,
|
||||
|
@ -63,6 +63,10 @@ enum TALER_ErrorCode
|
||||
*/
|
||||
TALER_EC_INTERNAL_INVARIANT_FAILURE = 5,
|
||||
|
||||
/**
|
||||
* Operation timed out.
|
||||
*/
|
||||
TALER_EC_TIMEOUT = 6,
|
||||
|
||||
/* ********** generic error codes ************* */
|
||||
|
||||
|
@ -59,13 +59,17 @@ struct TALER_WIRE_TransferDetails
|
||||
struct GNUNET_TIME_Absolute execution_date;
|
||||
|
||||
/**
|
||||
* Reserve public key that was encoded in the wire transfer subject.
|
||||
* FIXME (#5077): this is incorrect for *outgoing* wire transfers.
|
||||
* Maybe use `struct TALER_WireTransferIdentifierRawP` here instead?
|
||||
* OTOH, we might want to make this even more generic in case of
|
||||
* invalid transfers, so that we can capture those as well!
|
||||
* Binary data that was encoded in the wire transfer subject, if
|
||||
* it decoded properly. Otherwise all-zeros and @e wtid_s is set.
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* Wire transfer identifer as a string. Set to NULL if the
|
||||
* identifier was properly Base32 encoded and this @e wtid could be
|
||||
* set instead.
|
||||
*/
|
||||
char *wtid_s;
|
||||
|
||||
/**
|
||||
* The other account that was involved
|
||||
@ -93,6 +97,18 @@ typedef int
|
||||
const struct TALER_WIRE_TransferDetails *details);
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank to reject a wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ec status of the operation, #TALER_EC_NONE on success
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_WIRE_RejectTransferCallback) (void *cls,
|
||||
enum TALER_ErrorCode ec);
|
||||
|
||||
|
||||
/**
|
||||
* Handle returned for cancelling a preparation step.
|
||||
*/
|
||||
@ -308,12 +324,55 @@ struct TALER_WIRE_Plugin
|
||||
/**
|
||||
* Cancel going over the account's history.
|
||||
*
|
||||
* @param cls plugins' closure
|
||||
* @param whh operation to cancel
|
||||
*/
|
||||
void
|
||||
(*get_history_cancel) (void *cls,
|
||||
struct TALER_WIRE_HistoryHandle *whh);
|
||||
|
||||
|
||||
/**
|
||||
* Reject an incoming wire transfer that was obtained from the
|
||||
* history. This function can be used to transfer funds back to
|
||||
* the sender if the WTID was malformed (i.e. due to a typo).
|
||||
*
|
||||
* Calling `reject_transfer` twice on the same wire transfer should
|
||||
* be idempotent, i.e. not cause the funds to be wired back twice.
|
||||
* Furthermore, the transfer should henceforth be removed from the
|
||||
* results returned by @e get_history.
|
||||
*
|
||||
* @param cls plugin's closure
|
||||
* @param start_off offset of the wire transfer in plugin-specific format
|
||||
* @param start_off_len number of bytes in @a start_off
|
||||
* @param rej_cb function to call with the result of the operation
|
||||
* @param rej_cb_cls closure for @a rej_cb
|
||||
* @return handle to cancel the operation
|
||||
*/
|
||||
struct TALER_WIRE_RejectHandle *
|
||||
(*reject_transfer)(void *cls,
|
||||
const void *start_off,
|
||||
size_t start_off_len,
|
||||
TALER_WIRE_RejectTransferCallback rej_cb,
|
||||
void *rej_cb_cls);
|
||||
|
||||
/**
|
||||
* Cancel ongoing reject operation. Note that the rejection may still
|
||||
* proceed. Basically, if this function is called, the rejection may
|
||||
* have happened or not. This function is usually used during shutdown
|
||||
* or system upgrades. At a later point, the application must call
|
||||
* @e reject_transfer again for this wire transfer, unless the
|
||||
* @e get_history shows that the wire transfer no longer exists.
|
||||
*
|
||||
* @param cls plugins' closure
|
||||
* @param rh operation to cancel
|
||||
* @return closure of the callback of the operation
|
||||
*/
|
||||
void *
|
||||
(*reject_transfer_cancel)(void *cls,
|
||||
struct TALER_WIRE_RejectHandle *rh);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -791,6 +791,107 @@ sepa_get_history_cancel (void *cls,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Context for a rejection operation.
|
||||
*/
|
||||
struct TALER_WIRE_RejectHandle
|
||||
{
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_WIRE_RejectTransferCallback rej_cb;
|
||||
|
||||
/**
|
||||
* Closure for @e rej_cb.
|
||||
*/
|
||||
void *rej_cb_cls;
|
||||
|
||||
/**
|
||||
* Handle to task for timeout of operation.
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *timeout_task;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rejection operation failed with timeout, notify callback
|
||||
* and clean up.
|
||||
*
|
||||
* @param cls closure with `struct TALER_WIRE_RejectHandle`
|
||||
*/
|
||||
static void
|
||||
timeout_reject (void *cls)
|
||||
{
|
||||
struct TALER_WIRE_RejectHandle *rh = cls;
|
||||
|
||||
rh->timeout_task = NULL;
|
||||
rh->rej_cb (rh->rej_cb_cls,
|
||||
TALER_EC_NOT_IMPLEMENTED /* in the future: TALER_EC_TIMEOUT */);
|
||||
GNUNET_free (rh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reject an incoming wire transfer that was obtained from the
|
||||
* history. This function can be used to transfer funds back to
|
||||
* the sender if the WTID was malformed (i.e. due to a typo).
|
||||
*
|
||||
* Calling `reject_transfer` twice on the same wire transfer should
|
||||
* be idempotent, i.e. not cause the funds to be wired back twice.
|
||||
* Furthermore, the transfer should henceforth be removed from the
|
||||
* results returned by @e get_history.
|
||||
*
|
||||
* @param cls plugin's closure
|
||||
* @param start_off offset of the wire transfer in plugin-specific format
|
||||
* @param start_off_len number of bytes in @a start_off
|
||||
* @param rej_cb function to call with the result of the operation
|
||||
* @param rej_cb_cls closure for @a rej_cb
|
||||
* @return handle to cancel the operation
|
||||
*/
|
||||
static struct TALER_WIRE_RejectHandle *
|
||||
sepa_reject_transfer (void *cls,
|
||||
const void *start_off,
|
||||
size_t start_off_len,
|
||||
TALER_WIRE_RejectTransferCallback rej_cb,
|
||||
void *rej_cb_cls)
|
||||
{
|
||||
struct TALER_WIRE_RejectHandle *rh;
|
||||
|
||||
GNUNET_break (0); /* not implemented, just a stub! */
|
||||
rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
|
||||
rh->rej_cb = rej_cb;
|
||||
rh->rej_cb_cls = rej_cb_cls;
|
||||
rh->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_reject,
|
||||
rh);
|
||||
return rh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel ongoing reject operation. Note that the rejection may still
|
||||
* proceed. Basically, if this function is called, the rejection may
|
||||
* have happened or not. This function is usually used during shutdown
|
||||
* or system upgrades. At a later point, the application must call
|
||||
* @e reject_transfer again for this wire transfer, unless the
|
||||
* @e get_history shows that the wire transfer no longer exists.
|
||||
*
|
||||
* @param cls plugins' closure
|
||||
* @param rh operation to cancel
|
||||
* @return closure of the callback of the operation
|
||||
*/
|
||||
static void *
|
||||
sepa_reject_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_RejectHandle *rh)
|
||||
{
|
||||
void *ret = rh->rej_cb_cls;
|
||||
|
||||
GNUNET_SCHEDULER_cancel (rh->timeout_task);
|
||||
GNUNET_free (rh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize sepa-wire subsystem.
|
||||
*
|
||||
@ -832,6 +933,8 @@ libtaler_plugin_wire_sepa_init (void *cls)
|
||||
plugin->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
|
||||
plugin->get_history = &sepa_get_history;
|
||||
plugin->get_history_cancel = &sepa_get_history_cancel;
|
||||
plugin->reject_transfer = &sepa_reject_transfer;
|
||||
plugin->reject_transfer_cancel = &sepa_reject_transfer_cancel;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
@ -820,52 +820,52 @@ bhist_cb (void *cls,
|
||||
uint64_t bserial_id = GNUNET_htonll (serial_id);
|
||||
struct TALER_WIRE_TransferDetails wd;
|
||||
|
||||
if (MHD_HTTP_OK == http_status)
|
||||
{
|
||||
char *subject;
|
||||
char *space;
|
||||
switch (http_status) {
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
char *subject;
|
||||
char *space;
|
||||
|
||||
wd.amount = details->amount;
|
||||
wd.execution_date = details->execution_date;
|
||||
subject = GNUNET_strdup (details->wire_transfer_subject);
|
||||
space = strchr (subject, (int) ' ');
|
||||
if (NULL != space)
|
||||
{
|
||||
/* Space separates the actual wire transfer subject from the
|
||||
exchange base URL (if present, expected only for outgoing
|
||||
transactions). So we cut the string off at the space. */
|
||||
*space = '\0';
|
||||
}
|
||||
/* NOTE: For a real bank, the subject should include a checksum! */
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_STRINGS_string_to_data (subject,
|
||||
strlen (subject),
|
||||
&wd.reserve_pub,
|
||||
sizeof (wd.reserve_pub)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
wd.amount = details->amount;
|
||||
wd.execution_date = details->execution_date;
|
||||
subject = GNUNET_strdup (details->wire_transfer_subject);
|
||||
space = strchr (subject, (int) ' ');
|
||||
if (NULL != space)
|
||||
{
|
||||
/* Space separates the actual wire transfer subject from the
|
||||
exchange base URL (if present, expected only for outgoing
|
||||
transactions). So we cut the string off at the space. */
|
||||
*space = '\0';
|
||||
}
|
||||
/* NOTE: For a real bank, the subject should include a checksum! */
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_STRINGS_string_to_data (subject,
|
||||
strlen (subject),
|
||||
&wd.wtid,
|
||||
sizeof (wd.wtid)))
|
||||
{
|
||||
/* Ill-formed wire subject, set binary version to all zeros
|
||||
and pass as a string, this time including the part after
|
||||
the space. */
|
||||
memset (&wd.wtid,
|
||||
0,
|
||||
sizeof (wd.wtid));
|
||||
wd.wtid_s = details->wire_transfer_subject;
|
||||
}
|
||||
GNUNET_free (subject);
|
||||
/* NOTE: for a "real" bank, we would want to trigger logic to undo the
|
||||
wire transfer. However, for the "demo" bank, it should currently
|
||||
be "impossible" to do wire transfers with invalid subjects, and
|
||||
equally we thus don't need to undo them (and there is no API to do
|
||||
that nicely either right now). So we don't handle this case for now. */
|
||||
return;
|
||||
}
|
||||
GNUNET_free (subject);
|
||||
wd.account_details = details->account_details;
|
||||
wd.account_details = details->account_details;
|
||||
|
||||
if ( (NULL != whh->hres_cb) &&
|
||||
(GNUNET_OK !=
|
||||
whh->hres_cb (whh->hres_cb_cls,
|
||||
dir,
|
||||
&bserial_id,
|
||||
sizeof (bserial_id),
|
||||
&wd)) )
|
||||
whh->hres_cb = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (NULL != whh->hres_cb) &&
|
||||
(GNUNET_OK !=
|
||||
whh->hres_cb (whh->hres_cb_cls,
|
||||
dir,
|
||||
&bserial_id,
|
||||
sizeof (bserial_id),
|
||||
&wd)) )
|
||||
whh->hres_cb = NULL;
|
||||
break;
|
||||
}
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
if (NULL != whh->hres_cb)
|
||||
(void) whh->hres_cb (whh->hres_cb_cls,
|
||||
TALER_BANK_DIRECTION_NONE,
|
||||
@ -874,6 +874,20 @@ bhist_cb (void *cls,
|
||||
NULL);
|
||||
whh->hh = NULL;
|
||||
GNUNET_free (whh);
|
||||
break;
|
||||
default:
|
||||
/* FIXME: consider modifying API to pass more specific error code(s)
|
||||
back to the application. */
|
||||
GNUNET_break (0);
|
||||
if (NULL != whh->hres_cb)
|
||||
(void) whh->hres_cb (whh->hres_cb_cls,
|
||||
TALER_BANK_DIRECTION_NONE,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
whh->hh = NULL;
|
||||
GNUNET_free (whh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -975,6 +989,106 @@ test_get_history_cancel (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Context for a rejection operation.
|
||||
*/
|
||||
struct TALER_WIRE_RejectHandle
|
||||
{
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_WIRE_RejectTransferCallback rej_cb;
|
||||
|
||||
/**
|
||||
* Closure for @e rej_cb.
|
||||
*/
|
||||
void *rej_cb_cls;
|
||||
|
||||
/**
|
||||
* Handle to task for timeout of operation.
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *timeout_task;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rejection operation failed with timeout, notify callback
|
||||
* and clean up.
|
||||
*
|
||||
* @param cls closure with `struct TALER_WIRE_RejectHandle`
|
||||
*/
|
||||
static void
|
||||
timeout_reject (void *cls)
|
||||
{
|
||||
struct TALER_WIRE_RejectHandle *rh = cls;
|
||||
|
||||
rh->timeout_task = NULL;
|
||||
rh->rej_cb (rh->rej_cb_cls,
|
||||
TALER_EC_NOT_IMPLEMENTED /* in the future: TALER_EC_TIMEOUT */);
|
||||
GNUNET_free (rh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reject an incoming wire transfer that was obtained from the
|
||||
* history. This function can be used to transfer funds back to
|
||||
* the sender if the WTID was malformed (i.e. due to a typo).
|
||||
*
|
||||
* Calling `reject_transfer` twice on the same wire transfer should
|
||||
* be idempotent, i.e. not cause the funds to be wired back twice.
|
||||
* Furthermore, the transfer should henceforth be removed from the
|
||||
* results returned by @e get_history.
|
||||
*
|
||||
* @param cls plugin's closure
|
||||
* @param start_off offset of the wire transfer in plugin-specific format
|
||||
* @param start_off_len number of bytes in @a start_off
|
||||
* @param rej_cb function to call with the result of the operation
|
||||
* @param rej_cb_cls closure for @a rej_cb
|
||||
* @return handle to cancel the operation
|
||||
*/
|
||||
static struct TALER_WIRE_RejectHandle *
|
||||
test_reject_transfer (void *cls,
|
||||
const void *start_off,
|
||||
size_t start_off_len,
|
||||
TALER_WIRE_RejectTransferCallback rej_cb,
|
||||
void *rej_cb_cls)
|
||||
{
|
||||
struct TALER_WIRE_RejectHandle *rh;
|
||||
|
||||
GNUNET_break (0); /* not implemented, just a stub! */
|
||||
rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
|
||||
rh->rej_cb = rej_cb;
|
||||
rh->rej_cb_cls = rej_cb_cls;
|
||||
rh->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_reject,
|
||||
rh);
|
||||
return rh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel ongoing reject operation. Note that the rejection may still
|
||||
* proceed. Basically, if this function is called, the rejection may
|
||||
* have happened or not. This function is usually used during shutdown
|
||||
* or system upgrades. At a later point, the application must call
|
||||
* @e reject_transfer again for this wire transfer, unless the
|
||||
* @e get_history shows that the wire transfer no longer exists.
|
||||
*
|
||||
* @param cls plugins' closure
|
||||
* @param rh operation to cancel
|
||||
* @return closure of the callback of the operation
|
||||
*/
|
||||
static void *
|
||||
test_reject_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_RejectHandle *rh)
|
||||
{
|
||||
void *ret = rh->rej_cb_cls;
|
||||
|
||||
GNUNET_SCHEDULER_cancel (rh->timeout_task);
|
||||
GNUNET_free (rh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize test-wire subsystem.
|
||||
*
|
||||
@ -1087,6 +1201,8 @@ libtaler_plugin_wire_test_init (void *cls)
|
||||
plugin->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
|
||||
plugin->get_history = &test_get_history;
|
||||
plugin->get_history_cancel = &test_get_history_cancel;
|
||||
plugin->reject_transfer = &test_reject_transfer;
|
||||
plugin->reject_transfer_cancel = &test_reject_transfer_cancel;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
@ -211,9 +211,8 @@ history_result_cb (void *cls,
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (0 != memcmp (&wtid,
|
||||
&details->reserve_pub,
|
||||
GNUNET_MIN (sizeof (struct TALER_ReservePublicKeyP),
|
||||
sizeof (wtid))))
|
||||
&details->wtid,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
global_ret = GNUNET_SYSERR;
|
||||
|
Loading…
Reference in New Issue
Block a user