taler-mdb

GNU Taler Extensions and Integrations
Log | Files | Refs | Submodules | README | LICENSE

commit 95bfa5d0aab39df60778f5441abca997aa8a0d28
parent dc61ab0206f9d67c4142aaecda0ea420b7fd01b4
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat,  9 Nov 2019 16:09:15 +0100

misc cleanup

Diffstat:
Msrc/main.c | 209++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 149 insertions(+), 60 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -26,6 +26,7 @@ along with #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <termios.h> #include <nfc/nfc.h> #include <gnunet/platform.h> #include <gnunet/gnunet_util_lib.h> @@ -33,6 +34,17 @@ along with #define BACKEND_POLL_TIMEOUT GNUNET_TIME_UNIT_MINUTES +/** + * Timeout in milliseconds for libnfc operations. + */ +#define NFC_TIMEOUT 500 + +#define MAX_HTTP_RETRY_FREQ GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_MILLISECONDS, 500) + +/** + * Code returned by libnfc in case of success. + */ #define APDU_SUCCESS "\x90\x00" /* json order request keys */ @@ -79,6 +91,10 @@ struct PaymentActivity nfc_target nt; struct GNUNET_SCHEDULER_Task *task; + + struct GNUNET_SCHEDULER_Task *delay_task; + + int wallet_has_uri; }; @@ -111,21 +127,21 @@ static struct PaymentActivity *payment_activity; * GNUNET_CONFIGURATION_* iteration over values. */ static struct Product products[] = { -{ - .price = "0.1", - .description = "Snickers", - .key = 's' -}, -{ - .price = "0.1", - .description = "Twix", - .key = 't' -}, -{ - .price = NULL, - .description = NULL, - .key = '\0' -} + { + .price = "0.1", + .description = "Snickers", + .key = 's' + }, + { + .price = "0.1", + .description = "Twix", + .key = 't' + }, + { + .price = NULL, + .description = NULL, + .key = '\0' + } }; @@ -155,6 +171,8 @@ cleanup_payment (struct PaymentActivity *pa) TALER_MERCHANT_check_payment_cancel (pa->cpo); if (NULL != pa->task) GNUNET_SCHEDULER_cancel (pa->task); + if (NULL != pa->delay_task) + GNUNET_SCHEDULER_cancel (pa->delay_task); if (NULL != pa->pnd) { nfc_initiator_deselect_target (pa->pnd); // needed? @@ -170,11 +188,15 @@ static void shutdown_task (void *cls) { (void) cls; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutdown initiated\n"); if (NULL != context) { nfc_exit (context); context = NULL; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "NFC down\n"); if (NULL != payment_activity) { cleanup_payment (payment_activity); @@ -199,6 +221,10 @@ shutdown_task (void *cls) static void +check_payment_again (void *cls); + + +static void connect_target (void *cls); @@ -224,21 +250,39 @@ wallet_transmit_uri (void *cls) sizeof (message), response, sizeof(response), - 1 /* timeout, 1 ms */)) + NFC_TIMEOUT)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to send command\n"); pa->task = GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, - &wallet_select_aid, /* TBD: where to resume? */ - pa); + GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, + &wallet_select_aid, /* TBD: where to resume? */ + pa); return; } + if (0 == memcmp (response, + APDU_SUCCESS, + sizeof (response))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "PUT DATA command sent successfully\n"); + pa->wallet_has_uri = GNUNET_YES; + pa->delay_task = GNUNET_SCHEDULER_add_delayed (MAX_HTTP_RETRY_FREQ, + &check_payment_again, + pa); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "PUT DATA command transmission failed, return code: %x%x\n", + response[0], + response[1]); + } pa->task = GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, - &wallet_transmit_uri, /* TBD: where to resume? */ - pa); + GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, + &wallet_transmit_uri, /* TBD: where to resume? */ + pa); } @@ -253,19 +297,22 @@ wallet_select_aid (void *cls) memcpy (message, select_file, sizeof (select_file)); memcpy (&message[sizeof (select_file)], taler_aid, sizeof (taler_aid)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trying to find Taler wallet\n"); if (0 > nfc_initiator_transceive_bytes (pa->pnd, message, sizeof (message), response, - sizeof(response), - 10 /* timeout in ms */)) + sizeof (response), + NFC_TIMEOUT)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to select wallet app\n"); + "Failed to transceive with NFC app, trying to find another NFC client in 1s\n"); + nfc_initiator_deselect_target (pa->pnd); pa->task = GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, - &wallet_select_aid, /* TBD: where to resume? */ - pa); + GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, + &connect_target, + pa); return; } if (0 == memcmp (response, @@ -279,13 +326,14 @@ wallet_select_aid (void *cls) return; } GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "AID selection failure, return code: %x%x\n", + "AID selection failure, return code: %x%x, trying to find another NFC client in 1s\n", response[0], response[1]); + nfc_initiator_deselect_target (pa->pnd); pa->task = GNUNET_SCHEDULER_add_delayed ( - GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, - &wallet_select_aid, /* TBD: where to resume? */ - pa); + GNUNET_TIME_UNIT_SECONDS /* FIXME: timeout? */, + &connect_target, + pa); } @@ -306,6 +354,8 @@ connect_target (void *cls) pa->task = NULL; pa->nt.nti.nai.szUidLen = 0; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trying to find NFC client\n"); if (0 >= nfc_initiator_select_passive_target (pa->pnd, nmMifare[0], NULL, @@ -326,6 +376,8 @@ connect_target (void *cls) } else { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Found NFC client\n"); pa->task = GNUNET_SCHEDULER_add_now (&wallet_select_aid, pa); return; @@ -362,19 +414,19 @@ check_payment_cb (void *cls, struct TALER_Amount *refund_amount, const char *taler_pay_uri) { - (void)refunded; - (void)refund_amount; - (void)obj; + (void) refunded; + (void) refund_amount; + (void) obj; struct PaymentActivity *pa = cls; pa->cpo = NULL; // FIXME: check http_status, yada yada - if(MHD_HTTP_OK != http_status) + if (MHD_HTTP_OK != http_status) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, - "Http check payment failed: %u", - http_status); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Http check payment failed: %u", + http_status); cleanup_payment (pa); GNUNET_assert (payment_activity == pa); payment_activity = NULL; @@ -388,13 +440,13 @@ check_payment_cb (void *cls, } else { - pa->cpo = TALER_MERCHANT_check_payment (ctx, - backendBaseUrl, - pa->order_id, - NULL /* snack machine, no Web crap */, - BACKEND_POLL_TIMEOUT, - &check_payment_cb, - pa); + if (GNUNET_YES == pa->wallet_has_uri) + { + GNUNET_assert (NULL == pa->delay_task); + pa->delay_task = GNUNET_SCHEDULER_add_delayed (MAX_HTTP_RETRY_FREQ, + &check_payment_again, + pa); + } } if (NULL == pa->taler_pay_uri) { @@ -431,13 +483,30 @@ check_payment_cb (void *cls, static void +check_payment_again (void *cls) +{ + struct PaymentActivity *pa = cls; + + pa->delay_task = NULL; + GNUNET_assert (NULL == pa->cpo); + pa->cpo = TALER_MERCHANT_check_payment (ctx, + backendBaseUrl, + pa->order_id, + NULL /* snack machine, no Web crap */, + BACKEND_POLL_TIMEOUT, + &check_payment_cb, + pa); +} + + +static void proposal_cb (void *cls, unsigned int http_status, enum TALER_ErrorCode ec, const json_t *obj, const char *order_id) { - (void)obj; + (void) obj; struct PaymentActivity *pa = cls; pa->po = NULL; @@ -465,7 +534,7 @@ proposal_cb (void *cls, static struct PaymentActivity * - launch_payment (const struct Product *product) +launch_payment (const struct Product *product) { struct PaymentActivity *pa; json_t *orderReq; @@ -521,7 +590,7 @@ start_read_keyboard (void); static void read_keyboard_command (void *cls) { - (void)cls; + (void) cls; int input; keyboard_task = NULL; @@ -544,7 +613,6 @@ read_keyboard_command (void *cls) fprintf (stderr, "No purchase activity pending\n"); } - getchar(); start_read_keyboard (); return; } @@ -565,7 +633,6 @@ read_keyboard_command (void *cls) fprintf (stderr, "Unknown command '%c'\n", (char) input); - getchar(); start_read_keyboard (); } @@ -576,11 +643,11 @@ start_read_keyboard () struct GNUNET_DISK_FileHandle fh = { STDIN_FILENO }; GNUNET_assert (NULL == keyboard_task); - printf ("c' to cancel last purchase, 'x' to quit\n"); for (unsigned int i = 0; NULL != products[i].price; i++) printf ("'%c' to buy %s\n", products[i].key, products[i].description); + printf ("'c' to cancel last purchase\n'x' to quit\n"); printf ("Waiting for keyboard input\n"); keyboard_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, &fh, @@ -697,19 +764,41 @@ int main (int argc, char*const*argv) { + struct termios tty_opts_backup, tty_opts_raw; + int ret; /* the available command line options */ struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_OPTION_END }; + int have_tty; - if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, - argv, - "taler-mdb", - "This is an application for snack machines to pay with GNU Taler via nfc.\n", - options, - &run, - NULL)) + have_tty = isatty (STDIN_FILENO); + if (have_tty) + { + if (0 != tcgetattr (STDIN_FILENO, &tty_opts_backup)) + fprintf (stderr, + "Failed to get terminal discipline\n"); + tty_opts_raw = tty_opts_backup; + tty_opts_raw.c_lflag &= ~(ECHO | ECHONL | ICANON); + if (0 != tcsetattr (STDIN_FILENO, TCSANOW, &tty_opts_raw)) + fprintf (stderr, + "Failed to set terminal discipline\n"); + } + ret = GNUNET_PROGRAM_run (argc, + argv, + "taler-mdb", + "This is an application for snack machines to pay with GNU Taler via nfc.\n", + options, + &run, + NULL); + if (have_tty) + { + // Restore previous TTY settings + if (0 != tcsetattr (STDIN_FILENO, TCSANOW, &tty_opts_backup)) + fprintf (stderr, + "Failed to restore terminal discipline\n"); + } + if (GNUNET_OK != ret) return 1; return global_ret; }