diff --git a/configure.ac b/configure.ac index 8f06b520b..95457e5b4 100644 --- a/configure.ac +++ b/configure.ac @@ -357,6 +357,7 @@ AC_CONFIG_FILES([Makefile src/include/Makefile src/util/Makefile src/pq/Makefile + src/bank-lib/Makefile src/wire/Makefile src/mintdb/Makefile src/mint/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 986dcc5d3..ac839d52a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ if WALLET_ONLY SUBDIRS = include util else -SUBDIRS = include util $(PQ_DIR) wire mintdb mint mint-tools +SUBDIRS = include util $(PQ_DIR) bank-lib wire mintdb mint mint-tools if HAVE_LIBCURL SUBDIRS += mint-lib else diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h index b19e213a8..b292a7bcb 100644 --- a/src/include/taler_bank_service.h +++ b/src/include/taler_bank_service.h @@ -16,6 +16,7 @@ /** * @file include/taler_bank_service.h * @brief C interface of libtalerbank, a C library to use the Taler bank's HTTP API + * This is currently ONLY used to provide the "test" wire transfer protocol. * @author Christian Grothoff */ #ifndef _TALER_BANK_SERVICE_H diff --git a/src/wire/Makefile.am b/src/wire/Makefile.am index a27a59c78..64f50d97f 100644 --- a/src/wire/Makefile.am +++ b/src/wire/Makefile.am @@ -21,6 +21,7 @@ libtaler_plugin_wire_test_la_LIBADD = \ $(LTLIBINTL) libtaler_plugin_wire_test_la_LDFLAGS = \ $(TALER_PLUGIN_LDFLAGS) \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetutil $(XLIB) diff --git a/src/wire/plugin_wire_test.c b/src/wire/plugin_wire_test.c index 1ea856fd1..917cf09b6 100644 --- a/src/wire/plugin_wire_test.c +++ b/src/wire/plugin_wire_test.c @@ -17,13 +17,14 @@ /** * @file plugin_wire_test.c * @brief plugin for the "test" wire method - * @author Florian Dold * @author Christian Grothoff - * @author Sree Harsha Totakura */ #include "platform.h" #include "taler_wire_plugin.h" +#include "taler_bank_service.h" +/* only for HTTP status codes */ +#include /** * Type of the "cls" argument given to each of the functions in @@ -33,18 +34,164 @@ struct TestClosure { /** - * URI of the bank for sending funds to the bank. + * Handle to the bank for sending funds to the bank. */ - char *bank_uri; + struct TALER_BANK_Context *bank; /** * Which currency do we support? */ char *currency; + /** + * Handle to the bank task, or NULL. + */ + struct GNUNET_SCHEDULER_Task *bt; + }; +/** + * Handle returned by #test_prepare_wire_transfer. + */ +struct TALER_WIRE_PrepareHandle +{ + + /** + * Task we use for async execution. + */ + struct GNUNET_SCHEDULER_Task *task; + + /** + * Test closure we run in. + */ + struct TestClosure *tc; + + /** + * Wire data for the transfer. + */ + json_t *wire; + + /** + * Function to call with the serialized data. + */ + TALER_WIRE_PrepareTransactionCallback ptc; + + /** + * Closure for @e ptc. + */ + void *ptc_cls; + + /** + * Amount to transfer. + */ + struct TALER_Amount amount; + + /** + * Subject of the wire transfer. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + +}; + + +/** + * Handle returned by #test_execute_wire_transfer. + */ +struct TALER_WIRE_ExecuteHandle +{ + + /** + * Handle to the HTTP request to the bank. + */ + struct TALER_BANK_AdminAddIncomingHandle *aaih; + + /** + * Function to call with the result. + */ + TALER_WIRE_ConfirmationCallback cc; + + /** + * Closure for @e cc. + */ + void *cc_cls; +}; + + +/** + * Task that runs the bank's context's event loop with the GNUnet + * scheduler. + * + * @param cls our `struct TestClosure` + * @param tc scheduler context (unused) + */ +static void +context_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *sct) +{ + struct TestClosure *tc = cls; + long timeout; + int max_fd; + fd_set read_fd_set; + fd_set write_fd_set; + fd_set except_fd_set; + struct GNUNET_NETWORK_FDSet *rs; + struct GNUNET_NETWORK_FDSet *ws; + struct GNUNET_TIME_Relative delay; + + tc->bt = NULL; + TALER_BANK_perform (tc->bank); + max_fd = -1; + timeout = -1; + FD_ZERO (&read_fd_set); + FD_ZERO (&write_fd_set); + FD_ZERO (&except_fd_set); + TALER_BANK_get_select_info (tc->bank, + &read_fd_set, + &write_fd_set, + &except_fd_set, + &max_fd, + &timeout); + if (timeout >= 0) + delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout); + else + delay = GNUNET_TIME_UNIT_FOREVER_REL; + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (rs, + &read_fd_set, + max_fd + 1); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (ws, + &write_fd_set, + max_fd + 1); + tc->bt = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + delay, + rs, + ws, + &context_task, + cls); + GNUNET_NETWORK_fdset_destroy (rs); + GNUNET_NETWORK_fdset_destroy (ws); +} + + +/** + * Run the bank task now. + * + * @param tc context for which we should initiate running the task + */ +static void +run_bt (struct TestClosure *tc) +{ + if (NULL != tc->bt) + GNUNET_SCHEDULER_cancel (tc->bt); + tc->bt = GNUNET_SCHEDULER_add_now (&context_task, + tc); +} + + /** * Round amount DOWN to the amount that can be transferred via the wire * method. For example, Taler may support 0.000001 EUR as a unit of @@ -94,7 +241,33 @@ test_wire_validate (const json_t *wire) /** - * Prepare for exeuction of a wire transfer. + * Prepare for exeuction of a wire transfer. Calls the + * callback with the serialized state. + * + * @param cls the `struct TALER_WIRE_PrepareHandle` + * @param sct unused + */ +static void +do_prepare (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *sct) +{ + struct TALER_WIRE_PrepareHandle *pth = cls; + char buf[42]; // FIXME: init: serialize buf! + + pth->task = NULL; + pth->ptc (pth->ptc_cls, + buf, + sizeof (buf)); + GNUNET_free (pth); +} + + +/** + * Prepare for exeuction of a wire transfer. Note that we should call + * @a ptc asynchronously (as that is what the API requires, because + * some transfer methods need it). So while we could immediately call + * @a ptc, we first bundle up all the data and schedule a task to do + * the work. * * @param cls the @e cls of this struct with the plugin-specific state * @param wire valid wire account information @@ -112,8 +285,20 @@ test_prepare_wire_transfer (void *cls, TALER_WIRE_PrepareTransactionCallback ptc, void *ptc_cls) { - GNUNET_break (0); - return NULL; + struct TestClosure *tc = cls; + struct TALER_WIRE_PrepareHandle *pth; + + pth = GNUNET_new (struct TALER_WIRE_PrepareHandle); + pth->tc = tc; + pth->wire = (json_t *) wire; + json_incref (pth->wire); + pth->wtid = *wtid; + pth->ptc = ptc; + pth->ptc_cls = ptc_cls; + pth->amount = *amount; + pth->task = GNUNET_SCHEDULER_add_now (&do_prepare, + pth); + return pth; } @@ -128,7 +313,36 @@ static void test_prepare_wire_transfer_cancel (void *cls, struct TALER_WIRE_PrepareHandle *pth) { - GNUNET_break (0); + GNUNET_SCHEDULER_cancel (pth->task); + json_decref (pth->wire); + GNUNET_free (pth); +} + + +/** + * Called with the result of submitting information about an incoming + * transaction to a bank. + * + * @param cls closure with the `struct TALER_WIRE_ExecuteHandle` + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the bank's reply is bogus (fails to follow the protocol) + */ +static void +execute_cb (void *cls, + unsigned int http_status) +{ + struct TALER_WIRE_ExecuteHandle *eh = cls; + char s[14]; + + eh->aaih = NULL; + GNUNET_snprintf (s, + sizeof (s), + "%u", + http_status); + eh->cc (eh->cc_cls, + (MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR, + (MHD_HTTP_OK == http_status) ? NULL : s); + GNUNET_free (eh); } @@ -149,8 +363,32 @@ test_execute_wire_transfer (void *cls, TALER_WIRE_ConfirmationCallback cc, void *cc_cls) { - GNUNET_break (0); - return NULL; + struct TestClosure *tc = cls; + struct TALER_WIRE_ExecuteHandle *eh; + json_t *wire; + struct TALER_Amount amount; + struct TALER_WireTransferIdentifierRawP wtid; + + /* FIXME: deserialize buf */ + wire = NULL; + + eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle); + eh->cc = cc; + eh->cc_cls = cc_cls; + eh->aaih = TALER_BANK_admin_add_incoming (tc->bank, + &wtid, + &amount, + wire, + &execute_cb, + eh); + if (NULL == eh->aaih) + { + GNUNET_break (0); + GNUNET_free (eh); + return NULL; + } + run_bt (tc); + return eh; } @@ -170,7 +408,8 @@ static void test_execute_wire_transfer_cancel (void *cls, struct TALER_WIRE_ExecuteHandle *eh) { - GNUNET_break (0); + TALER_BANK_admin_add_incoming_cancel (eh->aaih); + GNUNET_free (eh); } @@ -186,21 +425,20 @@ libtaler_plugin_wire_test_init (void *cls) struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct TestClosure *tc; struct TALER_WIRE_Plugin *plugin; - - tc = GNUNET_new (struct TestClosure); + char *uri; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "wire-test", "bank_uri", - &tc->bank_uri)) - { + &uri)) + { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "wire-test", "bank_uri"); - GNUNET_free (tc); return NULL; } + tc = GNUNET_new (struct TestClosure); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "mint", @@ -210,7 +448,15 @@ libtaler_plugin_wire_test_init (void *cls) GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "mint", "CURRENCY"); - GNUNET_free (tc->bank_uri); + GNUNET_free (uri); + GNUNET_free (tc); + return NULL; + } + tc->bank = TALER_BANK_init (uri); + if (NULL == tc->bank) + { + GNUNET_break (0); + GNUNET_free (tc->currency); GNUNET_free (tc); return NULL; } @@ -239,7 +485,12 @@ libtaler_plugin_wire_test_done (void *cls) struct TALER_WIRE_Plugin *plugin = cls; struct TestClosure *tc = plugin->cls; - GNUNET_free (tc->bank_uri); + if (NULL != tc->bt) + { + GNUNET_SCHEDULER_cancel (tc->bt); + tc->bt = NULL; + } + TALER_BANK_fini (tc->bank); GNUNET_free (tc->currency); GNUNET_free (tc); GNUNET_free (plugin);