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.
|
* 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;
|
static struct GNUNET_CONTAINER_MultiHashMap *out_map;
|
||||||
|
|
||||||
@ -658,7 +659,9 @@ complain_out_not_found (void *cls,
|
|||||||
"row", (json_int_t) 0,
|
"row", (json_int_t) 0,
|
||||||
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
"amount_wired", TALER_JSON_from_amount (&roi->details.amount),
|
||||||
"amount_justified", TALER_JSON_from_amount (&zero),
|
"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),
|
"timestamp", GNUNET_STRINGS_absolute_time_to_string (roi->details.execution_date),
|
||||||
"diagnostic", "justification for wire transfer not found"));
|
"diagnostic", "justification for wire transfer not found"));
|
||||||
GNUNET_break (GNUNET_OK ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
@ -726,6 +729,7 @@ history_debit_cb (void *cls,
|
|||||||
const struct TALER_WIRE_TransferDetails *details)
|
const struct TALER_WIRE_TransferDetails *details)
|
||||||
{
|
{
|
||||||
struct ReserveOutInfo *roi;
|
struct ReserveOutInfo *roi;
|
||||||
|
struct GNUNET_HashCode rowh;
|
||||||
|
|
||||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||||
{
|
{
|
||||||
@ -735,13 +739,36 @@ history_debit_cb (void *cls,
|
|||||||
check_exchange_wire_out ();
|
check_exchange_wire_out ();
|
||||||
return GNUNET_OK;
|
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);
|
roi = GNUNET_new (struct ReserveOutInfo);
|
||||||
GNUNET_CRYPTO_hash (&details->reserve_pub, /* FIXME (#5077): missnomer */
|
GNUNET_CRYPTO_hash (&details->wtid,
|
||||||
sizeof (details->reserve_pub),
|
sizeof (details->wtid),
|
||||||
&roi->subject_hash);
|
&roi->subject_hash);
|
||||||
roi->details.amount = details->amount;
|
roi->details.amount = details->amount;
|
||||||
roi->details.execution_date = details->execution_date;
|
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);
|
roi->details.account_details = json_incref ((json_t *) details->account_details);
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_CONTAINER_multihashmap_put (out_map,
|
GNUNET_CONTAINER_multihashmap_put (out_map,
|
||||||
@ -749,13 +776,25 @@ history_debit_cb (void *cls,
|
|||||||
roi,
|
roi,
|
||||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
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,
|
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",
|
"table", "bank wire log",
|
||||||
"row", (json_int_t) 0,
|
"row", (json_int_t) 0,
|
||||||
"wire_offset_hash", GNUNET_JSON_from_data_auto (&roi->subject_hash),
|
"amount", TALER_JSON_from_amount (&details->amount),
|
||||||
"diagnostic", "duplicate wire offset"));
|
"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_SYSERR;
|
||||||
}
|
}
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
@ -830,7 +869,12 @@ reserve_in_cb (void *cls,
|
|||||||
rii->row_off_size = wire_reference_size;
|
rii->row_off_size = wire_reference_size;
|
||||||
rii->details.amount = *credit;
|
rii->details.amount = *credit;
|
||||||
rii->details.execution_date = execution_date;
|
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->details.account_details = json_incref ((json_t *) sender_account_details);
|
||||||
rii->rowid = rowid;
|
rii->rowid = rowid;
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
@ -875,7 +919,7 @@ complain_in_not_found (void *cls,
|
|||||||
"row", (json_int_t) rii->rowid,
|
"row", (json_int_t) rii->rowid,
|
||||||
"amount_expected", TALER_JSON_from_amount (&rii->details.amount),
|
"amount_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
"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),
|
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||||
"diagnostic", "incoming wire transfer claimed by exchange not found"));
|
"diagnostic", "incoming wire transfer claimed by exchange not found"));
|
||||||
GNUNET_break (GNUNET_OK ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
@ -966,16 +1010,16 @@ history_credit_cb (void *cls,
|
|||||||
"diagnostic", "wire reference size missmatch"));
|
"diagnostic", "wire reference size missmatch"));
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
if (0 != memcmp (&details->reserve_pub,
|
if (0 != memcmp (&details->wtid,
|
||||||
&rii->details.reserve_pub,
|
&rii->details.wtid,
|
||||||
sizeof (struct TALER_ReservePublicKeyP)))
|
sizeof (struct TALER_WireTransferIdentifierRawP)))
|
||||||
{
|
{
|
||||||
report (report_reserve_in_inconsistencies,
|
report (report_reserve_in_inconsistencies,
|
||||||
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
|
||||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||||
"amount_wired", TALER_JSON_from_amount (&zero),
|
"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),
|
"timestamp", GNUNET_STRINGS_absolute_time_to_string (rii->details.execution_date),
|
||||||
"diagnostic", "wire subject does not match"));
|
"diagnostic", "wire subject does not match"));
|
||||||
GNUNET_break (GNUNET_OK ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
@ -987,7 +1031,7 @@ history_credit_cb (void *cls,
|
|||||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||||
"amount_exchange_expected", TALER_JSON_from_amount (&zero),
|
"amount_exchange_expected", TALER_JSON_from_amount (&zero),
|
||||||
"amount_wired", TALER_JSON_from_amount (&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),
|
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||||
"diagnostic", "wire subject does not match"));
|
"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),
|
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
||||||
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
"amount_exchange_expected", TALER_JSON_from_amount (&rii->details.amount),
|
||||||
"amount_wired", TALER_JSON_from_amount (&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),
|
"timestamp", GNUNET_STRINGS_absolute_time_to_string (details->execution_date),
|
||||||
"diagnostic", "wire amount does not match"));
|
"diagnostic", "wire amount does not match"));
|
||||||
if (0 < TALER_amount_cmp (&details->amount,
|
if (0 < TALER_amount_cmp (&details->amount,
|
||||||
@ -1046,7 +1090,7 @@ history_credit_cb (void *cls,
|
|||||||
json_pack ("{s:s, s:o, s:o}",
|
json_pack ("{s:s, s:o, s:o}",
|
||||||
"amount", TALER_JSON_from_amount (&rii->details.amount),
|
"amount", TALER_JSON_from_amount (&rii->details.amount),
|
||||||
"row", GNUNET_JSON_from_data (row_off, row_off_size),
|
"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 ==
|
GNUNET_break (GNUNET_OK ==
|
||||||
TALER_amount_add (&total_missattribution_in,
|
TALER_amount_add (&total_missattribution_in,
|
||||||
&total_missattribution_in,
|
&total_missattribution_in,
|
||||||
|
@ -36,6 +36,23 @@
|
|||||||
#define DELAY GNUNET_TIME_UNIT_SECONDS
|
#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.
|
* Handle to the plugin.
|
||||||
*/
|
*/
|
||||||
@ -109,6 +126,11 @@ static struct GNUNET_SCHEDULER_Task *task;
|
|||||||
*/
|
*/
|
||||||
static struct TALER_WIRE_HistoryHandle *hh;
|
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.
|
* We're being aborted with CTRL-C (or SIGTERM). Shut down.
|
||||||
@ -129,6 +151,15 @@ shutdown_task (void *cls)
|
|||||||
hh);
|
hh);
|
||||||
hh = NULL;
|
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);
|
TALER_EXCHANGEDB_plugin_unload (db_plugin);
|
||||||
db_plugin = NULL;
|
db_plugin = NULL;
|
||||||
TALER_WIRE_plugin_unload (wire_plugin);
|
TALER_WIRE_plugin_unload (wire_plugin);
|
||||||
@ -204,6 +235,48 @@ static void
|
|||||||
find_transfers (void *cls);
|
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
|
* Callbacks of this type are used to serve the result of asking
|
||||||
* the bank for the transaction history.
|
* the bank for the transaction history.
|
||||||
@ -224,6 +297,7 @@ history_cb (void *cls,
|
|||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_Session *session = cls;
|
struct TALER_EXCHANGEDB_Session *session = cls;
|
||||||
enum GNUNET_DB_QueryStatus qs;
|
enum GNUNET_DB_QueryStatus qs;
|
||||||
|
struct TALER_ReservePublicKeyP reserve_pub;
|
||||||
|
|
||||||
if (TALER_BANK_DIRECTION_NONE == dir)
|
if (TALER_BANK_DIRECTION_NONE == dir)
|
||||||
{
|
{
|
||||||
@ -254,13 +328,45 @@ history_cb (void *cls,
|
|||||||
NULL);
|
NULL);
|
||||||
return GNUNET_OK; /* will be ignored anyway */
|
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,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Adding wire transfer over %s with subject `%s'\n",
|
"Adding wire transfer over %s with subject `%s'\n",
|
||||||
TALER_amount2s (&details->amount),
|
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,
|
qs = db_plugin->reserves_in_insert (db_plugin->cls,
|
||||||
session,
|
session,
|
||||||
&details->reserve_pub,
|
&reserve_pub,
|
||||||
&details->amount,
|
&details->amount,
|
||||||
details->execution_date,
|
details->execution_date,
|
||||||
details->account_details,
|
details->account_details,
|
||||||
|
@ -63,6 +63,10 @@ enum TALER_ErrorCode
|
|||||||
*/
|
*/
|
||||||
TALER_EC_INTERNAL_INVARIANT_FAILURE = 5,
|
TALER_EC_INTERNAL_INVARIANT_FAILURE = 5,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation timed out.
|
||||||
|
*/
|
||||||
|
TALER_EC_TIMEOUT = 6,
|
||||||
|
|
||||||
/* ********** generic error codes ************* */
|
/* ********** generic error codes ************* */
|
||||||
|
|
||||||
|
@ -59,13 +59,17 @@ struct TALER_WIRE_TransferDetails
|
|||||||
struct GNUNET_TIME_Absolute execution_date;
|
struct GNUNET_TIME_Absolute execution_date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserve public key that was encoded in the wire transfer subject.
|
* Binary data that was encoded in the wire transfer subject, if
|
||||||
* FIXME (#5077): this is incorrect for *outgoing* wire transfers.
|
* it decoded properly. Otherwise all-zeros and @e wtid_s is set.
|
||||||
* 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!
|
|
||||||
*/
|
*/
|
||||||
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
|
* The other account that was involved
|
||||||
@ -93,6 +97,18 @@ typedef int
|
|||||||
const struct TALER_WIRE_TransferDetails *details);
|
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.
|
* Handle returned for cancelling a preparation step.
|
||||||
*/
|
*/
|
||||||
@ -308,12 +324,55 @@ struct TALER_WIRE_Plugin
|
|||||||
/**
|
/**
|
||||||
* Cancel going over the account's history.
|
* Cancel going over the account's history.
|
||||||
*
|
*
|
||||||
|
* @param cls plugins' closure
|
||||||
* @param whh operation to cancel
|
* @param whh operation to cancel
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
(*get_history_cancel) (void *cls,
|
(*get_history_cancel) (void *cls,
|
||||||
struct TALER_WIRE_HistoryHandle *whh);
|
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.
|
* 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->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
|
||||||
plugin->get_history = &sepa_get_history;
|
plugin->get_history = &sepa_get_history;
|
||||||
plugin->get_history_cancel = &sepa_get_history_cancel;
|
plugin->get_history_cancel = &sepa_get_history_cancel;
|
||||||
|
plugin->reject_transfer = &sepa_reject_transfer;
|
||||||
|
plugin->reject_transfer_cancel = &sepa_reject_transfer_cancel;
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,52 +820,52 @@ bhist_cb (void *cls,
|
|||||||
uint64_t bserial_id = GNUNET_htonll (serial_id);
|
uint64_t bserial_id = GNUNET_htonll (serial_id);
|
||||||
struct TALER_WIRE_TransferDetails wd;
|
struct TALER_WIRE_TransferDetails wd;
|
||||||
|
|
||||||
if (MHD_HTTP_OK == http_status)
|
switch (http_status) {
|
||||||
{
|
case MHD_HTTP_OK:
|
||||||
char *subject;
|
{
|
||||||
char *space;
|
char *subject;
|
||||||
|
char *space;
|
||||||
|
|
||||||
wd.amount = details->amount;
|
wd.amount = details->amount;
|
||||||
wd.execution_date = details->execution_date;
|
wd.execution_date = details->execution_date;
|
||||||
subject = GNUNET_strdup (details->wire_transfer_subject);
|
subject = GNUNET_strdup (details->wire_transfer_subject);
|
||||||
space = strchr (subject, (int) ' ');
|
space = strchr (subject, (int) ' ');
|
||||||
if (NULL != space)
|
if (NULL != space)
|
||||||
{
|
{
|
||||||
/* Space separates the actual wire transfer subject from the
|
/* Space separates the actual wire transfer subject from the
|
||||||
exchange base URL (if present, expected only for outgoing
|
exchange base URL (if present, expected only for outgoing
|
||||||
transactions). So we cut the string off at the space. */
|
transactions). So we cut the string off at the space. */
|
||||||
*space = '\0';
|
*space = '\0';
|
||||||
}
|
}
|
||||||
/* NOTE: For a real bank, the subject should include a checksum! */
|
/* NOTE: For a real bank, the subject should include a checksum! */
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
GNUNET_STRINGS_string_to_data (subject,
|
GNUNET_STRINGS_string_to_data (subject,
|
||||||
strlen (subject),
|
strlen (subject),
|
||||||
&wd.reserve_pub,
|
&wd.wtid,
|
||||||
sizeof (wd.reserve_pub)))
|
sizeof (wd.wtid)))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
/* 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);
|
GNUNET_free (subject);
|
||||||
/* NOTE: for a "real" bank, we would want to trigger logic to undo the
|
wd.account_details = details->account_details;
|
||||||
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;
|
|
||||||
|
|
||||||
if ( (NULL != whh->hres_cb) &&
|
if ( (NULL != whh->hres_cb) &&
|
||||||
(GNUNET_OK !=
|
(GNUNET_OK !=
|
||||||
whh->hres_cb (whh->hres_cb_cls,
|
whh->hres_cb (whh->hres_cb_cls,
|
||||||
dir,
|
dir,
|
||||||
&bserial_id,
|
&bserial_id,
|
||||||
sizeof (bserial_id),
|
sizeof (bserial_id),
|
||||||
&wd)) )
|
&wd)) )
|
||||||
whh->hres_cb = NULL;
|
whh->hres_cb = NULL;
|
||||||
}
|
break;
|
||||||
else
|
}
|
||||||
{
|
case MHD_HTTP_NO_CONTENT:
|
||||||
if (NULL != whh->hres_cb)
|
if (NULL != whh->hres_cb)
|
||||||
(void) whh->hres_cb (whh->hres_cb_cls,
|
(void) whh->hres_cb (whh->hres_cb_cls,
|
||||||
TALER_BANK_DIRECTION_NONE,
|
TALER_BANK_DIRECTION_NONE,
|
||||||
@ -874,6 +874,20 @@ bhist_cb (void *cls,
|
|||||||
NULL);
|
NULL);
|
||||||
whh->hh = NULL;
|
whh->hh = NULL;
|
||||||
GNUNET_free (whh);
|
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.
|
* 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->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
|
||||||
plugin->get_history = &test_get_history;
|
plugin->get_history = &test_get_history;
|
||||||
plugin->get_history_cancel = &test_get_history_cancel;
|
plugin->get_history_cancel = &test_get_history_cancel;
|
||||||
|
plugin->reject_transfer = &test_reject_transfer;
|
||||||
|
plugin->reject_transfer_cancel = &test_reject_transfer_cancel;
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,9 +211,8 @@ history_result_cb (void *cls,
|
|||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
if (0 != memcmp (&wtid,
|
if (0 != memcmp (&wtid,
|
||||||
&details->reserve_pub,
|
&details->wtid,
|
||||||
GNUNET_MIN (sizeof (struct TALER_ReservePublicKeyP),
|
sizeof (struct TALER_WireTransferIdentifierRawP)))
|
||||||
sizeof (wtid))))
|
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
global_ret = GNUNET_SYSERR;
|
global_ret = GNUNET_SYSERR;
|
||||||
|
Loading…
Reference in New Issue
Block a user