diff options
Diffstat (limited to 'src/bank-lib/fakebank.c')
-rw-r--r-- | src/bank-lib/fakebank.c | 716 |
1 files changed, 636 insertions, 80 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index ecb5934e6..580012b02 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c | |||
@@ -21,11 +21,12 @@ | |||
21 | * @brief library that fakes being a Taler bank for testcases | 21 | * @brief library that fakes being a Taler bank for testcases |
22 | * @author Christian Grothoff <christian@grothoff.org> | 22 | * @author Christian Grothoff <christian@grothoff.org> |
23 | */ | 23 | */ |
24 | // TODO: support long polling | ||
25 | // TODO: support adding WAD transfers | 24 | // TODO: support adding WAD transfers |
26 | 25 | ||
27 | #include "platform.h" | 26 | #include "platform.h" |
28 | #include <pthread.h> | 27 | #include <pthread.h> |
28 | #include <poll.h> | ||
29 | #include <sys/eventfd.h> | ||
29 | #include "taler_fakebank_lib.h" | 30 | #include "taler_fakebank_lib.h" |
30 | #include "taler_bank_service.h" | 31 | #include "taler_bank_service.h" |
31 | #include "taler_mhd_lib.h" | 32 | #include "taler_mhd_lib.h" |
@@ -44,6 +45,73 @@ | |||
44 | #define MAX_URL_LEN 64 | 45 | #define MAX_URL_LEN 64 |
45 | 46 | ||
46 | /** | 47 | /** |
48 | * Per account information. | ||
49 | */ | ||
50 | struct Account; | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Types of long polling activities. | ||
55 | */ | ||
56 | enum LongPollType | ||
57 | { | ||
58 | /** | ||
59 | * Transfer TO the exchange. | ||
60 | */ | ||
61 | LP_CREDIT, | ||
62 | |||
63 | /** | ||
64 | * Transfer FROM the exchange. | ||
65 | */ | ||
66 | LP_DEBIT | ||
67 | |||
68 | }; | ||
69 | |||
70 | /** | ||
71 | * Client waiting for activity on this account. | ||
72 | */ | ||
73 | struct LongPoller | ||
74 | { | ||
75 | |||
76 | /** | ||
77 | * Kept in a DLL. | ||
78 | */ | ||
79 | struct LongPoller *next; | ||
80 | |||
81 | /** | ||
82 | * Kept in a DLL. | ||
83 | */ | ||
84 | struct LongPoller *prev; | ||
85 | |||
86 | /** | ||
87 | * Account this long poller is waiting on. | ||
88 | */ | ||
89 | struct Account *account; | ||
90 | |||
91 | /** | ||
92 | * Entry in the heap for this long poller. | ||
93 | */ | ||
94 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
95 | |||
96 | /** | ||
97 | * Client that is waiting for transactions. | ||
98 | */ | ||
99 | struct MHD_Connection *conn; | ||
100 | |||
101 | /** | ||
102 | * When will this long poller time out? | ||
103 | */ | ||
104 | struct GNUNET_TIME_Absolute timeout; | ||
105 | |||
106 | /** | ||
107 | * What does the @e connection wait for? | ||
108 | */ | ||
109 | enum LongPollType type; | ||
110 | |||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
47 | * Details about a transcation we (as the simulated bank) received. | 115 | * Details about a transcation we (as the simulated bank) received. |
48 | */ | 116 | */ |
49 | struct Transaction; | 117 | struct Transaction; |
@@ -75,6 +143,16 @@ struct Account | |||
75 | struct Transaction *out_tail; | 143 | struct Transaction *out_tail; |
76 | 144 | ||
77 | /** | 145 | /** |
146 | * Kept in a DLL. | ||
147 | */ | ||
148 | struct LongPoller *lp_head; | ||
149 | |||
150 | /** | ||
151 | * Kept in a DLL. | ||
152 | */ | ||
153 | struct LongPoller *lp_tail; | ||
154 | |||
155 | /** | ||
78 | * Account name (string, not payto!) | 156 | * Account name (string, not payto!) |
79 | */ | 157 | */ |
80 | char *account_name; | 158 | char *account_name; |
@@ -257,6 +335,23 @@ struct TALER_FAKEBANK_Handle | |||
257 | struct GNUNET_SCHEDULER_Task *mhd_task; | 335 | struct GNUNET_SCHEDULER_Task *mhd_task; |
258 | 336 | ||
259 | /** | 337 | /** |
338 | * Task for expiring long-polling connections, | ||
339 | * unless we are using a thread pool (then NULL). | ||
340 | */ | ||
341 | struct GNUNET_SCHEDULER_Task *lp_task; | ||
342 | |||
343 | /** | ||
344 | * Task for expiring long-polling connections, unless we are using the | ||
345 | * GNUnet scheduler (then NULL). | ||
346 | */ | ||
347 | pthread_t lp_thread; | ||
348 | |||
349 | /** | ||
350 | * MIN-heap of long pollers, sorted by timeout. | ||
351 | */ | ||
352 | struct GNUNET_CONTAINER_Heap *lp_heap; | ||
353 | |||
354 | /** | ||
260 | * Hashmap of reserve public keys to | 355 | * Hashmap of reserve public keys to |
261 | * `struct Transaction` with that reserve public | 356 | * `struct Transaction` with that reserve public |
262 | * key. Used to prevent public-key re-use. | 357 | * key. Used to prevent public-key re-use. |
@@ -319,6 +414,17 @@ struct TALER_FAKEBANK_Handle | |||
319 | */ | 414 | */ |
320 | uint16_t port; | 415 | uint16_t port; |
321 | 416 | ||
417 | /** | ||
418 | * Event FD to signal @a lp_thread a change in | ||
419 | * @a lp_heap. | ||
420 | */ | ||
421 | int lp_event; | ||
422 | |||
423 | /** | ||
424 | * Set to true once we are shutting down. | ||
425 | */ | ||
426 | bool in_shutdown; | ||
427 | |||
322 | #if EPOLL_SUPPORT | 428 | #if EPOLL_SUPPORT |
323 | /** | 429 | /** |
324 | * Boxed @e mhd_fd. | 430 | * Boxed @e mhd_fd. |
@@ -334,6 +440,145 @@ struct TALER_FAKEBANK_Handle | |||
334 | 440 | ||
335 | 441 | ||
336 | /** | 442 | /** |
443 | * Special address "con_cls" can point to to indicate that the handler has | ||
444 | * been called more than once already (was previously suspended). | ||
445 | */ | ||
446 | static int special_ptr; | ||
447 | |||
448 | |||
449 | /** | ||
450 | * Task run whenever HTTP server operations are pending. | ||
451 | * | ||
452 | * @param cls the `struct TALER_FAKEBANK_Handle` | ||
453 | */ | ||
454 | static void | ||
455 | run_mhd (void *cls); | ||
456 | |||
457 | |||
458 | /** | ||
459 | * Trigger the @a lp. Frees associated resources, | ||
460 | * except the entry of @a lp in the timeout heap. | ||
461 | * Must be called while the ``big lock`` is held. | ||
462 | * | ||
463 | * @param[in] lp long poller to trigger | ||
464 | * @param[in,out] h fakebank handle | ||
465 | */ | ||
466 | static void | ||
467 | lp_trigger (struct LongPoller *lp, | ||
468 | struct TALER_FAKEBANK_Handle *h) | ||
469 | { | ||
470 | struct Account *acc = lp->account; | ||
471 | |||
472 | GNUNET_CONTAINER_DLL_remove (acc->lp_head, | ||
473 | acc->lp_tail, | ||
474 | lp); | ||
475 | MHD_resume_connection (lp->conn); | ||
476 | GNUNET_free (lp); | ||
477 | if (NULL != h->mhd_task) | ||
478 | GNUNET_SCHEDULER_cancel (h->mhd_task); | ||
479 | h->mhd_task = | ||
480 | GNUNET_SCHEDULER_add_now (&run_mhd, | ||
481 | h); | ||
482 | } | ||
483 | |||
484 | |||
485 | /** | ||
486 | * Thread that is run to wake up connections that have hit their timeout. Runs | ||
487 | * until in_shutdown is set to true. Must be send signals via lp_event on | ||
488 | * shutdown and/or whenever the heap changes to an earlier timeout. | ||
489 | * | ||
490 | * @param cls a `struct TALER_FAKEBANK_Handle *` | ||
491 | * @return NULL | ||
492 | */ | ||
493 | static void * | ||
494 | lp_expiration_thread (void *cls) | ||
495 | { | ||
496 | struct TALER_FAKEBANK_Handle *h = cls; | ||
497 | |||
498 | GNUNET_assert (0 == | ||
499 | pthread_mutex_lock (&h->big_lock)); | ||
500 | while (! h->in_shutdown) | ||
501 | { | ||
502 | struct LongPoller *lp; | ||
503 | int timeout_ms; | ||
504 | |||
505 | lp = GNUNET_CONTAINER_heap_peek (h->lp_heap); | ||
506 | while ( (NULL != lp) && | ||
507 | GNUNET_TIME_absolute_is_past (lp->timeout)) | ||
508 | { | ||
509 | GNUNET_assert (lp == | ||
510 | GNUNET_CONTAINER_heap_remove_root (h->lp_heap)); | ||
511 | GNUNET_assert (0 == | ||
512 | pthread_mutex_lock (&h->big_lock)); | ||
513 | lp_trigger (lp, | ||
514 | h); | ||
515 | GNUNET_assert (0 == | ||
516 | pthread_mutex_unlock (&h->big_lock)); | ||
517 | lp = GNUNET_CONTAINER_heap_peek (h->lp_heap); | ||
518 | } | ||
519 | if (NULL != lp) | ||
520 | { | ||
521 | struct GNUNET_TIME_Relative rem; | ||
522 | unsigned long long left_ms; | ||
523 | |||
524 | rem = GNUNET_TIME_absolute_get_remaining (lp->timeout); | ||
525 | left_ms = rem.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; | ||
526 | if (left_ms > INT_MAX) | ||
527 | timeout_ms = INT_MAX; | ||
528 | else | ||
529 | timeout_ms = (int) left_ms; | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | timeout_ms = -1; /* infinity */ | ||
534 | } | ||
535 | GNUNET_assert (0 == | ||
536 | pthread_mutex_unlock (&h->big_lock)); | ||
537 | { | ||
538 | struct pollfd p = { | ||
539 | .fd = h->lp_event, | ||
540 | .events = POLLIN | ||
541 | }; | ||
542 | int ret; | ||
543 | |||
544 | ret = poll (&p, | ||
545 | 1, | ||
546 | timeout_ms); | ||
547 | if (-1 == ret) | ||
548 | { | ||
549 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
550 | "poll"); | ||
551 | } | ||
552 | else if (1 == ret) | ||
553 | { | ||
554 | /* clear event */ | ||
555 | uint64_t ev; | ||
556 | ssize_t iret; | ||
557 | |||
558 | iret = read (h->lp_event, | ||
559 | &ev, | ||
560 | sizeof (ev)); | ||
561 | if (-1 == iret) | ||
562 | { | ||
563 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
564 | "read"); | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | GNUNET_break (sizeof (uint64_t) == iret); | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | GNUNET_assert (0 == | ||
573 | pthread_mutex_lock (&h->big_lock)); | ||
574 | } | ||
575 | GNUNET_assert (0 == | ||
576 | pthread_mutex_unlock (&h->big_lock)); | ||
577 | return NULL; | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
337 | * Lookup account with @a name, and if it does not exist, create it. | 582 | * Lookup account with @a name, and if it does not exist, create it. |
338 | * | 583 | * |
339 | * @param[in,out] h bank to lookup account at | 584 | * @param[in,out] h bank to lookup account at |
@@ -626,6 +871,36 @@ post_transaction (struct TALER_FAKEBANK_Handle *h, | |||
626 | ca->in_tail, | 871 | ca->in_tail, |
627 | old); | 872 | old); |
628 | } | 873 | } |
874 | { | ||
875 | struct LongPoller *nxt; | ||
876 | |||
877 | for (struct LongPoller *lp = debit_acc->lp_head; | ||
878 | NULL != lp; | ||
879 | lp = nxt) | ||
880 | { | ||
881 | nxt = lp->next; | ||
882 | if (LP_DEBIT == lp->type) | ||
883 | { | ||
884 | GNUNET_assert (lp == | ||
885 | GNUNET_CONTAINER_heap_remove_node (lp->hn)); | ||
886 | lp_trigger (lp, | ||
887 | h); | ||
888 | } | ||
889 | } | ||
890 | for (struct LongPoller *lp = credit_acc->lp_head; | ||
891 | NULL != lp; | ||
892 | lp = nxt) | ||
893 | { | ||
894 | nxt = lp->next; | ||
895 | if (LP_CREDIT == lp->type) | ||
896 | { | ||
897 | GNUNET_assert (lp == | ||
898 | GNUNET_CONTAINER_heap_remove_node (lp->hn)); | ||
899 | lp_trigger (lp, | ||
900 | h); | ||
901 | } | ||
902 | } | ||
903 | } | ||
629 | GNUNET_assert (0 == | 904 | GNUNET_assert (0 == |
630 | pthread_mutex_unlock (&h->big_lock)); | 905 | pthread_mutex_unlock (&h->big_lock)); |
631 | if ( (NULL != old) && | 906 | if ( (NULL != old) && |
@@ -884,6 +1159,7 @@ free_account (void *cls, | |||
884 | { | 1159 | { |
885 | struct Account *account = val; | 1160 | struct Account *account = val; |
886 | 1161 | ||
1162 | GNUNET_assert (NULL == account->lp_head); | ||
887 | GNUNET_free (account->account_name); | 1163 | GNUNET_free (account->account_name); |
888 | GNUNET_free (account); | 1164 | GNUNET_free (account); |
889 | return GNUNET_OK; | 1165 | return GNUNET_OK; |
@@ -898,6 +1174,11 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h) | |||
898 | GNUNET_SCHEDULER_cancel (h->mhd_task); | 1174 | GNUNET_SCHEDULER_cancel (h->mhd_task); |
899 | h->mhd_task = NULL; | 1175 | h->mhd_task = NULL; |
900 | } | 1176 | } |
1177 | if (NULL != h->lp_task) | ||
1178 | { | ||
1179 | GNUNET_SCHEDULER_cancel (h->lp_task); | ||
1180 | h->lp_task = NULL; | ||
1181 | } | ||
901 | #if EPOLL_SUPPORT | 1182 | #if EPOLL_SUPPORT |
902 | if (NULL != h->mhd_rfd) | 1183 | if (NULL != h->mhd_rfd) |
903 | { | 1184 | { |
@@ -910,6 +1191,39 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h) | |||
910 | MHD_stop_daemon (h->mhd_bank); | 1191 | MHD_stop_daemon (h->mhd_bank); |
911 | h->mhd_bank = NULL; | 1192 | h->mhd_bank = NULL; |
912 | } | 1193 | } |
1194 | if (-1 != h->lp_event) | ||
1195 | { | ||
1196 | uint64_t val = 1; | ||
1197 | void *ret; | ||
1198 | struct LongPoller *lp; | ||
1199 | |||
1200 | GNUNET_assert (0 == | ||
1201 | pthread_mutex_lock (&h->big_lock)); | ||
1202 | h->in_shutdown = true; | ||
1203 | while (NULL != (lp = GNUNET_CONTAINER_heap_remove_root (h->lp_heap))) | ||
1204 | lp_trigger (lp, | ||
1205 | h); | ||
1206 | GNUNET_break (sizeof (val) == | ||
1207 | write (h->lp_event, | ||
1208 | &val, | ||
1209 | sizeof (val))); | ||
1210 | GNUNET_assert (0 == | ||
1211 | pthread_mutex_unlock (&h->big_lock)); | ||
1212 | GNUNET_break (0 == | ||
1213 | pthread_join (h->lp_thread, | ||
1214 | &ret)); | ||
1215 | GNUNET_break (NULL == ret); | ||
1216 | GNUNET_break (0 == close (h->lp_event)); | ||
1217 | h->lp_event = -1; | ||
1218 | } | ||
1219 | else | ||
1220 | { | ||
1221 | struct LongPoller *lp; | ||
1222 | |||
1223 | while (NULL != (lp = GNUNET_CONTAINER_heap_remove_root (h->lp_heap))) | ||
1224 | lp_trigger (lp, | ||
1225 | h); | ||
1226 | } | ||
913 | if (NULL != h->accounts) | 1227 | if (NULL != h->accounts) |
914 | { | 1228 | { |
915 | GNUNET_CONTAINER_multihashmap_iterate (h->accounts, | 1229 | GNUNET_CONTAINER_multihashmap_iterate (h->accounts, |
@@ -919,6 +1233,7 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h) | |||
919 | } | 1233 | } |
920 | GNUNET_CONTAINER_multihashmap_destroy (h->uuid_map); | 1234 | GNUNET_CONTAINER_multihashmap_destroy (h->uuid_map); |
921 | GNUNET_CONTAINER_multipeermap_destroy (h->rpubs); | 1235 | GNUNET_CONTAINER_multipeermap_destroy (h->rpubs); |
1236 | GNUNET_CONTAINER_heap_destroy (h->lp_heap); | ||
922 | GNUNET_assert (0 == | 1237 | GNUNET_assert (0 == |
923 | pthread_mutex_destroy (&h->big_lock)); | 1238 | pthread_mutex_destroy (&h->big_lock)); |
924 | GNUNET_assert (0 == | 1239 | GNUNET_assert (0 == |
@@ -960,6 +1275,10 @@ handle_mhd_completion_callback (void *cls, | |||
960 | (void) cls; | 1275 | (void) cls; |
961 | (void) connection; | 1276 | (void) connection; |
962 | (void) toe; | 1277 | (void) toe; |
1278 | if (NULL == *con_cls) | ||
1279 | return; | ||
1280 | if (&special_ptr == *con_cls) | ||
1281 | return; | ||
963 | GNUNET_JSON_post_parser_cleanup (*con_cls); | 1282 | GNUNET_JSON_post_parser_cleanup (*con_cls); |
964 | *con_cls = NULL; | 1283 | *con_cls = NULL; |
965 | } | 1284 | } |
@@ -988,7 +1307,6 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, | |||
988 | json_t *json; | 1307 | json_t *json; |
989 | uint64_t row_id; | 1308 | uint64_t row_id; |
990 | struct GNUNET_TIME_Absolute timestamp; | 1309 | struct GNUNET_TIME_Absolute timestamp; |
991 | enum GNUNET_GenericReturnValue ret; | ||
992 | 1310 | ||
993 | pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, | 1311 | pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, |
994 | connection, | 1312 | connection, |
@@ -1017,6 +1335,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, | |||
1017 | struct TALER_Amount amount; | 1335 | struct TALER_Amount amount; |
1018 | struct TALER_ReservePublicKeyP reserve_pub; | 1336 | struct TALER_ReservePublicKeyP reserve_pub; |
1019 | char *debit; | 1337 | char *debit; |
1338 | enum GNUNET_GenericReturnValue ret; | ||
1020 | struct GNUNET_JSON_Specification spec[] = { | 1339 | struct GNUNET_JSON_Specification spec[] = { |
1021 | GNUNET_JSON_spec_fixed_auto ("reserve_pub", | 1340 | GNUNET_JSON_spec_fixed_auto ("reserve_pub", |
1022 | &reserve_pub), | 1341 | &reserve_pub), |
@@ -1029,14 +1348,13 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, | |||
1029 | }; | 1348 | }; |
1030 | 1349 | ||
1031 | if (GNUNET_OK != | 1350 | if (GNUNET_OK != |
1032 | GNUNET_JSON_parse (json, | 1351 | (ret = TALER_MHD_parse_json_data (connection, |
1033 | spec, | 1352 | json, |
1034 | NULL, NULL)) | 1353 | spec))) |
1035 | { | 1354 | { |
1036 | GNUNET_break (0); | 1355 | GNUNET_break_op (0); |
1037 | json_decref (json); | 1356 | json_decref (json); |
1038 | /* We're fakebank, no need for nice error handling */ | 1357 | return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; |
1039 | return MHD_NO; | ||
1040 | } | 1358 | } |
1041 | if (0 != strcasecmp (amount.currency, | 1359 | if (0 != strcasecmp (amount.currency, |
1042 | h->currency)) | 1360 | h->currency)) |
@@ -1141,6 +1459,7 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h, | |||
1141 | char *credit; | 1459 | char *credit; |
1142 | const char *base_url; | 1460 | const char *base_url; |
1143 | struct TALER_Amount amount; | 1461 | struct TALER_Amount amount; |
1462 | enum GNUNET_GenericReturnValue ret; | ||
1144 | struct GNUNET_JSON_Specification spec[] = { | 1463 | struct GNUNET_JSON_Specification spec[] = { |
1145 | GNUNET_JSON_spec_fixed_auto ("request_uid", | 1464 | GNUNET_JSON_spec_fixed_auto ("request_uid", |
1146 | &uuid), | 1465 | &uuid), |
@@ -1157,14 +1476,13 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h, | |||
1157 | }; | 1476 | }; |
1158 | 1477 | ||
1159 | if (GNUNET_OK != | 1478 | if (GNUNET_OK != |
1160 | GNUNET_JSON_parse (json, | 1479 | (ret = TALER_MHD_parse_json_data (connection, |
1161 | spec, | 1480 | json, |
1162 | NULL, NULL)) | 1481 | spec))) |
1163 | { | 1482 | { |
1164 | GNUNET_break (0); | 1483 | GNUNET_break_op (0); |
1165 | json_decref (json); | 1484 | json_decref (json); |
1166 | /* We are fakebank, no need for nice error handling */ | 1485 | return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; |
1167 | return MHD_NO; | ||
1168 | } | 1486 | } |
1169 | { | 1487 | { |
1170 | int ret; | 1488 | int ret; |
@@ -1223,20 +1541,17 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h, | |||
1223 | * | 1541 | * |
1224 | * @param h the fakebank handle | 1542 | * @param h the fakebank handle |
1225 | * @param connection the connection | 1543 | * @param connection the connection |
1226 | * @param con_cls place to store state, not used | ||
1227 | * @return MHD result code | 1544 | * @return MHD result code |
1228 | */ | 1545 | */ |
1229 | static MHD_RESULT | 1546 | static MHD_RESULT |
1230 | handle_home_page (struct TALER_FAKEBANK_Handle *h, | 1547 | handle_home_page (struct TALER_FAKEBANK_Handle *h, |
1231 | struct MHD_Connection *connection, | 1548 | struct MHD_Connection *connection) |
1232 | void **con_cls) | ||
1233 | { | 1549 | { |
1234 | MHD_RESULT ret; | 1550 | MHD_RESULT ret; |
1235 | struct MHD_Response *resp; | 1551 | struct MHD_Response *resp; |
1236 | #define HELLOMSG "Hello, Fakebank!" | 1552 | #define HELLOMSG "Hello, Fakebank!" |
1237 | 1553 | ||
1238 | (void) h; | 1554 | (void) h; |
1239 | (void) con_cls; | ||
1240 | resp = MHD_create_response_from_buffer ( | 1555 | resp = MHD_create_response_from_buffer ( |
1241 | strlen (HELLOMSG), | 1556 | strlen (HELLOMSG), |
1242 | HELLOMSG, | 1557 | HELLOMSG, |
@@ -1292,9 +1607,11 @@ struct HistoryArgs | |||
1292 | * @param h bank handle to work on | 1607 | * @param h bank handle to work on |
1293 | * @param connection MHD connection. | 1608 | * @param connection MHD connection. |
1294 | * @param[out] ha will contain the parsed values. | 1609 | * @param[out] ha will contain the parsed values. |
1295 | * @return #GNUNET_OK only if the parsing succeeds. | 1610 | * @return #GNUNET_OK only if the parsing succeeds, |
1611 | * #GNUNET_SYSERR if it failed, | ||
1612 | * #GNUNET_NO if it failed and an error was returned | ||
1296 | */ | 1613 | */ |
1297 | static int | 1614 | static enum GNUNET_GenericReturnValue |
1298 | parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, | 1615 | parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, |
1299 | struct MHD_Connection *connection, | 1616 | struct MHD_Connection *connection, |
1300 | struct HistoryArgs *ha) | 1617 | struct HistoryArgs *ha) |
@@ -1305,6 +1622,7 @@ parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, | |||
1305 | unsigned long long lp_timeout; | 1622 | unsigned long long lp_timeout; |
1306 | unsigned long long sval; | 1623 | unsigned long long sval; |
1307 | long long d; | 1624 | long long d; |
1625 | char dummy; | ||
1308 | 1626 | ||
1309 | start = MHD_lookup_connection_value (connection, | 1627 | start = MHD_lookup_connection_value (connection, |
1310 | MHD_GET_ARGUMENT_KIND, | 1628 | MHD_GET_ARGUMENT_KIND, |
@@ -1319,23 +1637,60 @@ parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, | |||
1319 | lp_timeout = 0; | 1637 | lp_timeout = 0; |
1320 | if ( (NULL == delta) || | 1638 | if ( (NULL == delta) || |
1321 | (1 != sscanf (delta, | 1639 | (1 != sscanf (delta, |
1322 | "%lld", | 1640 | "%lld%c", |
1323 | &d)) || | 1641 | &d, |
1324 | ( (NULL != long_poll_ms) && | 1642 | &dummy)) ) |
1325 | (1 != sscanf (long_poll_ms, | ||
1326 | "%llu", | ||
1327 | &lp_timeout)) ) || | ||
1328 | ( (NULL != start) && | ||
1329 | (1 != sscanf (start, | ||
1330 | "%llu", | ||
1331 | &sval)) ) ) | ||
1332 | { | 1643 | { |
1333 | /* Fail if one of the above failed. */ | 1644 | /* Fail if one of the above failed. */ |
1334 | /* Invalid request, given that this is fakebank we impolitely | 1645 | /* Invalid request, given that this is fakebank we impolitely |
1335 | * just kill the connection instead of returning a nice error. | 1646 | * just kill the connection instead of returning a nice error. |
1336 | */ | 1647 | */ |
1337 | GNUNET_break (0); | 1648 | GNUNET_break_op (0); |
1338 | return GNUNET_NO; | 1649 | return (MHD_YES == |
1650 | TALER_MHD_reply_with_error (connection, | ||
1651 | MHD_HTTP_BAD_REQUEST, | ||
1652 | TALER_EC_GENERIC_PARAMETER_MALFORMED, | ||
1653 | "delta")) | ||
1654 | ? GNUNET_NO | ||
1655 | : GNUNET_SYSERR; | ||
1656 | } | ||
1657 | if ( (NULL != long_poll_ms) && | ||
1658 | (1 != sscanf (long_poll_ms, | ||
1659 | "%llu%c", | ||
1660 | &lp_timeout, | ||
1661 | &dummy)) ) | ||
1662 | { | ||
1663 | /* Fail if one of the above failed. */ | ||
1664 | /* Invalid request, given that this is fakebank we impolitely | ||
1665 | * just kill the connection instead of returning a nice error. | ||
1666 | */ | ||
1667 | GNUNET_break_op (0); | ||
1668 | return (MHD_YES == | ||
1669 | TALER_MHD_reply_with_error (connection, | ||
1670 | MHD_HTTP_BAD_REQUEST, | ||
1671 | TALER_EC_GENERIC_PARAMETER_MALFORMED, | ||
1672 | "long_poll_ms")) | ||
1673 | ? GNUNET_NO | ||
1674 | : GNUNET_SYSERR; | ||
1675 | } | ||
1676 | if ( (NULL != start) && | ||
1677 | (1 != sscanf (start, | ||
1678 | "%llu%c", | ||
1679 | &sval, | ||
1680 | &dummy)) ) | ||
1681 | { | ||
1682 | /* Fail if one of the above failed. */ | ||
1683 | /* Invalid request, given that this is fakebank we impolitely | ||
1684 | * just kill the connection instead of returning a nice error. | ||
1685 | */ | ||
1686 | GNUNET_break_op (0); | ||
1687 | return (MHD_YES == | ||
1688 | TALER_MHD_reply_with_error (connection, | ||
1689 | MHD_HTTP_BAD_REQUEST, | ||
1690 | TALER_EC_GENERIC_PARAMETER_MALFORMED, | ||
1691 | "start")) | ||
1692 | ? GNUNET_NO | ||
1693 | : GNUNET_SYSERR; | ||
1339 | } | 1694 | } |
1340 | if (NULL == start) | 1695 | if (NULL == start) |
1341 | ha->start_idx = (d > 0) ? 0 : h->serial_counter; | 1696 | ha->start_idx = (d > 0) ? 0 : h->serial_counter; |
@@ -1344,8 +1699,14 @@ parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, | |||
1344 | ha->delta = (int64_t) d; | 1699 | ha->delta = (int64_t) d; |
1345 | if (0 == ha->delta) | 1700 | if (0 == ha->delta) |
1346 | { | 1701 | { |
1347 | GNUNET_break (0); | 1702 | GNUNET_break_op (0); |
1348 | return GNUNET_NO; | 1703 | return (MHD_YES == |
1704 | TALER_MHD_reply_with_error (connection, | ||
1705 | MHD_HTTP_BAD_REQUEST, | ||
1706 | TALER_EC_GENERIC_PARAMETER_MALFORMED, | ||
1707 | "delta")) | ||
1708 | ? GNUNET_NO | ||
1709 | : GNUNET_SYSERR; | ||
1349 | } | 1710 | } |
1350 | ha->lp_timeout | 1711 | ha->lp_timeout |
1351 | = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | 1712 | = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, |
@@ -1359,33 +1720,146 @@ parse_history_common_args (const struct TALER_FAKEBANK_Handle *h, | |||
1359 | 1720 | ||
1360 | 1721 | ||
1361 | /** | 1722 | /** |
1723 | * Task run when a long poller is about to time out. | ||
1724 | * Only used in single-threaded mode. | ||
1725 | * | ||
1726 | * @param cls a `struct TALER_FAKEBANK_Handle *` | ||
1727 | */ | ||
1728 | static void | ||
1729 | lp_timeout (void *cls) | ||
1730 | { | ||
1731 | struct TALER_FAKEBANK_Handle *h = cls; | ||
1732 | struct LongPoller *lp; | ||
1733 | |||
1734 | h->lp_task = NULL; | ||
1735 | while (NULL != (lp = GNUNET_CONTAINER_heap_peek (h->lp_heap))) | ||
1736 | { | ||
1737 | if (GNUNET_TIME_absolute_is_future (lp->timeout)) | ||
1738 | break; | ||
1739 | GNUNET_assert (lp == | ||
1740 | GNUNET_CONTAINER_heap_remove_root (h->lp_heap)); | ||
1741 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1742 | "Timeout reached for long poller %p\n", | ||
1743 | lp->conn); | ||
1744 | lp_trigger (lp, | ||
1745 | h); | ||
1746 | } | ||
1747 | if (NULL == lp) | ||
1748 | return; | ||
1749 | h->lp_task = GNUNET_SCHEDULER_add_at (lp->timeout, | ||
1750 | &lp_timeout, | ||
1751 | h); | ||
1752 | } | ||
1753 | |||
1754 | |||
1755 | /** | ||
1756 | * Reschedule the timeout task of @a h for time @a t. | ||
1757 | * | ||
1758 | * @param h fakebank handle | ||
1759 | * @param t when will the next connection timeout expire | ||
1760 | */ | ||
1761 | static void | ||
1762 | reschedule_lp_timeout (struct TALER_FAKEBANK_Handle *h, | ||
1763 | struct GNUNET_TIME_Absolute t) | ||
1764 | { | ||
1765 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1766 | "Scheduling timeout task for %s\n", | ||
1767 | GNUNET_STRINGS_absolute_time_to_string (t)); | ||
1768 | if (-1 != h->lp_event) | ||
1769 | { | ||
1770 | uint64_t num = 1; | ||
1771 | |||
1772 | GNUNET_break (sizeof (num) == | ||
1773 | write (h->lp_event, | ||
1774 | &num, | ||
1775 | sizeof (num))); | ||
1776 | } | ||
1777 | else | ||
1778 | { | ||
1779 | if (NULL != h->lp_task) | ||
1780 | GNUNET_SCHEDULER_cancel (h->lp_task); | ||
1781 | h->lp_task = GNUNET_SCHEDULER_add_at (t, | ||
1782 | &lp_timeout, | ||
1783 | h); | ||
1784 | } | ||
1785 | } | ||
1786 | |||
1787 | |||
1788 | /** | ||
1789 | * Start long-polling for @a connection and @a acc | ||
1790 | * for transfers in @a dir. Must be called with the | ||
1791 | * "big lock" held. | ||
1792 | * | ||
1793 | * @param[in,out] h fakebank handle | ||
1794 | * @param[in,out] connection to suspend | ||
1795 | * @param[in,out] acc account affected | ||
1796 | * @param lp_timeout how long to suspend | ||
1797 | * @param dir direction of transfers to watch for | ||
1798 | */ | ||
1799 | static void | ||
1800 | start_lp (struct TALER_FAKEBANK_Handle *h, | ||
1801 | struct MHD_Connection *connection, | ||
1802 | struct Account *acc, | ||
1803 | struct GNUNET_TIME_Relative lp_timeout, | ||
1804 | enum LongPollType dir) | ||
1805 | { | ||
1806 | struct LongPoller *lp; | ||
1807 | bool toc; | ||
1808 | |||
1809 | lp = GNUNET_new (struct LongPoller); | ||
1810 | lp->account = acc; | ||
1811 | lp->conn = connection; | ||
1812 | lp->timeout = GNUNET_TIME_relative_to_absolute (lp_timeout); | ||
1813 | lp->type = dir; | ||
1814 | lp->hn = GNUNET_CONTAINER_heap_insert (h->lp_heap, | ||
1815 | lp, | ||
1816 | lp->timeout.abs_value_us); | ||
1817 | toc = (lp == | ||
1818 | GNUNET_CONTAINER_heap_peek (h->lp_heap)); | ||
1819 | GNUNET_CONTAINER_DLL_insert (acc->lp_head, | ||
1820 | acc->lp_tail, | ||
1821 | lp); | ||
1822 | MHD_suspend_connection (connection); | ||
1823 | if (toc) | ||
1824 | reschedule_lp_timeout (h, | ||
1825 | lp->timeout); | ||
1826 | |||
1827 | } | ||
1828 | |||
1829 | |||
1830 | /** | ||
1362 | * Handle incoming HTTP request for /history/outgoing | 1831 | * Handle incoming HTTP request for /history/outgoing |
1363 | * | 1832 | * |
1364 | * @param h the fakebank handle | 1833 | * @param h the fakebank handle |
1365 | * @param connection the connection | 1834 | * @param connection the connection |
1366 | * @param account which account the request is about | 1835 | * @param account which account the request is about |
1367 | * @return MHD result code | 1836 | * @param con_cls closure for request (NULL or &special_ptr) |
1368 | */ | 1837 | */ |
1369 | static MHD_RESULT | 1838 | static MHD_RESULT |
1370 | handle_debit_history (struct TALER_FAKEBANK_Handle *h, | 1839 | handle_debit_history (struct TALER_FAKEBANK_Handle *h, |
1371 | struct MHD_Connection *connection, | 1840 | struct MHD_Connection *connection, |
1372 | const char *account) | 1841 | const char *account, |
1842 | void **con_cls) | ||
1373 | { | 1843 | { |
1374 | struct HistoryArgs ha; | 1844 | struct HistoryArgs ha; |
1375 | struct Account *acc; | 1845 | struct Account *acc; |
1376 | struct Transaction *pos; | 1846 | struct Transaction *pos; |
1377 | json_t *history; | 1847 | json_t *history; |
1378 | char *debit_payto; | 1848 | char *debit_payto; |
1849 | enum GNUNET_GenericReturnValue ret; | ||
1379 | 1850 | ||
1851 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1852 | "Handling /history/outgoing connection %p\n", | ||
1853 | connection); | ||
1380 | if (GNUNET_OK != | 1854 | if (GNUNET_OK != |
1381 | parse_history_common_args (h, | 1855 | (ret = parse_history_common_args (h, |
1382 | connection, | 1856 | connection, |
1383 | &ha)) | 1857 | &ha))) |
1384 | { | 1858 | { |
1385 | GNUNET_break (0); | 1859 | return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; |
1386 | return MHD_NO; | ||
1387 | } | 1860 | } |
1388 | 1861 | if (&special_ptr == *con_cls) | |
1862 | ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; | ||
1389 | acc = lookup_account (h, | 1863 | acc = lookup_account (h, |
1390 | account); | 1864 | account); |
1391 | GNUNET_asprintf (&debit_payto, | 1865 | GNUNET_asprintf (&debit_payto, |
@@ -1430,16 +1904,29 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, | |||
1430 | if ( (NULL == t) || | 1904 | if ( (NULL == t) || |
1431 | overflow) | 1905 | overflow) |
1432 | { | 1906 | { |
1907 | GNUNET_free (debit_payto); | ||
1908 | if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && | ||
1909 | (0 < ha.delta)) | ||
1910 | { | ||
1911 | GNUNET_assert (0 == | ||
1912 | pthread_mutex_unlock (&h->big_lock)); | ||
1913 | return TALER_MHD_REPLY_JSON_PACK ( | ||
1914 | connection, | ||
1915 | MHD_HTTP_OK, | ||
1916 | GNUNET_JSON_pack_array_steal ( | ||
1917 | "outgoing_transactions", | ||
1918 | history)); | ||
1919 | } | ||
1920 | *con_cls = &special_ptr; | ||
1921 | start_lp (h, | ||
1922 | connection, | ||
1923 | acc, | ||
1924 | ha.lp_timeout, | ||
1925 | LP_DEBIT); | ||
1433 | GNUNET_assert (0 == | 1926 | GNUNET_assert (0 == |
1434 | pthread_mutex_unlock (&h->big_lock)); | 1927 | pthread_mutex_unlock (&h->big_lock)); |
1435 | GNUNET_free (debit_payto); | 1928 | json_decref (history); |
1436 | /* FIXME: suspend for long-polling instead */ | 1929 | return MHD_YES; |
1437 | return TALER_MHD_REPLY_JSON_PACK ( | ||
1438 | connection, | ||
1439 | MHD_HTTP_OK, | ||
1440 | GNUNET_JSON_pack_array_steal ( | ||
1441 | "outgoing_transactions", | ||
1442 | history)); | ||
1443 | } | 1930 | } |
1444 | if (t->debit_account != acc) | 1931 | if (t->debit_account != acc) |
1445 | { | 1932 | { |
@@ -1524,6 +2011,21 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, | |||
1524 | if (0 < ha.delta) | 2011 | if (0 < ha.delta) |
1525 | pos = pos->next_out; | 2012 | pos = pos->next_out; |
1526 | } | 2013 | } |
2014 | if ( (0 == json_array_size (history)) && | ||
2015 | (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && | ||
2016 | (0 < ha.delta)) | ||
2017 | { | ||
2018 | *con_cls = &special_ptr; | ||
2019 | start_lp (h, | ||
2020 | connection, | ||
2021 | acc, | ||
2022 | ha.lp_timeout, | ||
2023 | LP_DEBIT); | ||
2024 | GNUNET_assert (0 == | ||
2025 | pthread_mutex_unlock (&h->big_lock)); | ||
2026 | json_decref (history); | ||
2027 | return MHD_YES; | ||
2028 | } | ||
1527 | GNUNET_assert (0 == | 2029 | GNUNET_assert (0 == |
1528 | pthread_mutex_unlock (&h->big_lock)); | 2030 | pthread_mutex_unlock (&h->big_lock)); |
1529 | GNUNET_free (debit_payto); | 2031 | GNUNET_free (debit_payto); |
@@ -1546,22 +2048,29 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, | |||
1546 | static MHD_RESULT | 2048 | static MHD_RESULT |
1547 | handle_credit_history (struct TALER_FAKEBANK_Handle *h, | 2049 | handle_credit_history (struct TALER_FAKEBANK_Handle *h, |
1548 | struct MHD_Connection *connection, | 2050 | struct MHD_Connection *connection, |
1549 | const char *account) | 2051 | const char *account, |
2052 | void **con_cls) | ||
1550 | { | 2053 | { |
1551 | struct HistoryArgs ha; | 2054 | struct HistoryArgs ha; |
1552 | struct Account *acc; | 2055 | struct Account *acc; |
1553 | const struct Transaction *pos; | 2056 | const struct Transaction *pos; |
1554 | json_t *history; | 2057 | json_t *history; |
1555 | char *credit_payto; | 2058 | char *credit_payto; |
2059 | enum GNUNET_GenericReturnValue ret; | ||
1556 | 2060 | ||
2061 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2062 | "Handling /history/incoming connection %p\n", | ||
2063 | connection); | ||
1557 | if (GNUNET_OK != | 2064 | if (GNUNET_OK != |
1558 | parse_history_common_args (h, | 2065 | (ret = parse_history_common_args (h, |
1559 | connection, | 2066 | connection, |
1560 | &ha)) | 2067 | &ha))) |
1561 | { | 2068 | { |
1562 | GNUNET_break (0); | 2069 | return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; |
1563 | return MHD_NO; | ||
1564 | } | 2070 | } |
2071 | if (&special_ptr == *con_cls) | ||
2072 | ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; | ||
2073 | *con_cls = &special_ptr; | ||
1565 | acc = lookup_account (h, | 2074 | acc = lookup_account (h, |
1566 | account); | 2075 | account); |
1567 | history = json_array (); | 2076 | history = json_array (); |
@@ -1601,15 +2110,28 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, | |||
1601 | if ( (NULL == t) || | 2110 | if ( (NULL == t) || |
1602 | overflow) | 2111 | overflow) |
1603 | { | 2112 | { |
2113 | GNUNET_free (credit_payto); | ||
2114 | if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && | ||
2115 | (0 < ha.delta)) | ||
2116 | { | ||
2117 | GNUNET_assert (0 == | ||
2118 | pthread_mutex_unlock (&h->big_lock)); | ||
2119 | return TALER_MHD_REPLY_JSON_PACK (connection, | ||
2120 | MHD_HTTP_OK, | ||
2121 | GNUNET_JSON_pack_array_steal ( | ||
2122 | "incoming_transactions", | ||
2123 | history)); | ||
2124 | } | ||
2125 | *con_cls = &special_ptr; | ||
2126 | start_lp (h, | ||
2127 | connection, | ||
2128 | acc, | ||
2129 | ha.lp_timeout, | ||
2130 | LP_CREDIT); | ||
1604 | GNUNET_assert (0 == | 2131 | GNUNET_assert (0 == |
1605 | pthread_mutex_unlock (&h->big_lock)); | 2132 | pthread_mutex_unlock (&h->big_lock)); |
1606 | GNUNET_free (credit_payto); | 2133 | json_decref (history); |
1607 | /* FIXME: suspend for long-polling instead */ | 2134 | return MHD_YES; |
1608 | return TALER_MHD_REPLY_JSON_PACK (connection, | ||
1609 | MHD_HTTP_OK, | ||
1610 | GNUNET_JSON_pack_array_steal ( | ||
1611 | "incoming_transactions", | ||
1612 | history)); | ||
1613 | } | 2135 | } |
1614 | if (skip) | 2136 | if (skip) |
1615 | { | 2137 | { |
@@ -1681,6 +2203,21 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, | |||
1681 | if (0 < ha.delta) | 2203 | if (0 < ha.delta) |
1682 | pos = pos->next_in; | 2204 | pos = pos->next_in; |
1683 | } | 2205 | } |
2206 | if ( (0 == json_array_size (history)) && | ||
2207 | (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && | ||
2208 | (0 < ha.delta)) | ||
2209 | { | ||
2210 | *con_cls = &special_ptr; | ||
2211 | start_lp (h, | ||
2212 | connection, | ||
2213 | acc, | ||
2214 | ha.lp_timeout, | ||
2215 | LP_CREDIT); | ||
2216 | GNUNET_assert (0 == | ||
2217 | pthread_mutex_unlock (&h->big_lock)); | ||
2218 | json_decref (history); | ||
2219 | return MHD_YES; | ||
2220 | } | ||
1684 | GNUNET_assert (0 == | 2221 | GNUNET_assert (0 == |
1685 | pthread_mutex_unlock (&h->big_lock)); | 2222 | pthread_mutex_unlock (&h->big_lock)); |
1686 | GNUNET_free (credit_payto); | 2223 | GNUNET_free (credit_payto); |
@@ -1702,7 +2239,7 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, | |||
1702 | * @param account which account should process the request | 2239 | * @param account which account should process the request |
1703 | * @param upload_data request data | 2240 | * @param upload_data request data |
1704 | * @param upload_data_size size of @a upload_data in bytes | 2241 | * @param upload_data_size size of @a upload_data in bytes |
1705 | * @param con_cls closure for request (a `struct Buffer *`) | 2242 | * @param con_cls closure |
1706 | * @return MHD result code | 2243 | * @return MHD result code |
1707 | */ | 2244 | */ |
1708 | static MHD_RESULT | 2245 | static MHD_RESULT |
@@ -1727,18 +2264,19 @@ serve (struct TALER_FAKEBANK_Handle *h, | |||
1727 | (NULL != account) ) | 2264 | (NULL != account) ) |
1728 | return handle_credit_history (h, | 2265 | return handle_credit_history (h, |
1729 | connection, | 2266 | connection, |
1730 | account); | 2267 | account, |
2268 | con_cls); | ||
1731 | if ( (0 == strcmp (url, | 2269 | if ( (0 == strcmp (url, |
1732 | "/history/outgoing")) && | 2270 | "/history/outgoing")) && |
1733 | (NULL != account) ) | 2271 | (NULL != account) ) |
1734 | return handle_debit_history (h, | 2272 | return handle_debit_history (h, |
1735 | connection, | 2273 | connection, |
1736 | account); | 2274 | account, |
2275 | con_cls); | ||
1737 | if (0 == strcmp (url, | 2276 | if (0 == strcmp (url, |
1738 | "/")) | 2277 | "/")) |
1739 | return handle_home_page (h, | 2278 | return handle_home_page (h, |
1740 | connection, | 2279 | connection); |
1741 | con_cls); | ||
1742 | } | 2280 | } |
1743 | else if (0 == strcasecmp (method, | 2281 | else if (0 == strcasecmp (method, |
1744 | MHD_HTTP_METHOD_POST)) | 2282 | MHD_HTTP_METHOD_POST)) |
@@ -1762,12 +2300,15 @@ serve (struct TALER_FAKEBANK_Handle *h, | |||
1762 | con_cls); | 2300 | con_cls); |
1763 | } | 2301 | } |
1764 | /* Unexpected URL path, just close the connection. */ | 2302 | /* Unexpected URL path, just close the connection. */ |
1765 | /* We're rather impolite here, but it's a testcase. */ | ||
1766 | TALER_LOG_ERROR ("Breaking URL: %s %s\n", | 2303 | TALER_LOG_ERROR ("Breaking URL: %s %s\n", |
1767 | method, | 2304 | method, |
1768 | url); | 2305 | url); |
1769 | GNUNET_break_op (0); | 2306 | GNUNET_break_op (0); |
1770 | return MHD_NO; | 2307 | return TALER_MHD_reply_with_error ( |
2308 | connection, | ||
2309 | MHD_HTTP_NOT_FOUND, | ||
2310 | TALER_EC_GENERIC_ENDPOINT_UNKNOWN, | ||
2311 | url); | ||
1771 | } | 2312 | } |
1772 | 2313 | ||
1773 | 2314 | ||
@@ -1781,7 +2322,7 @@ serve (struct TALER_FAKEBANK_Handle *h, | |||
1781 | * @param version HTTP version (ignored) | 2322 | * @param version HTTP version (ignored) |
1782 | * @param upload_data request data | 2323 | * @param upload_data request data |
1783 | * @param upload_data_size size of @a upload_data in bytes | 2324 | * @param upload_data_size size of @a upload_data in bytes |
1784 | * @param con_cls closure for request (a `struct Buffer *`) | 2325 | * @param con_cls closure for request |
1785 | * @return MHD result code | 2326 | * @return MHD result code |
1786 | */ | 2327 | */ |
1787 | static MHD_RESULT | 2328 | static MHD_RESULT |
@@ -1823,15 +2364,6 @@ handle_mhd_request (void *cls, | |||
1823 | } | 2364 | } |
1824 | 2365 | ||
1825 | 2366 | ||
1826 | /** | ||
1827 | * Task run whenever HTTP server operations are pending. | ||
1828 | * | ||
1829 | * @param cls the `struct TALER_FAKEBANK_Handle` | ||
1830 | */ | ||
1831 | static void | ||
1832 | run_mhd (void *cls); | ||
1833 | |||
1834 | |||
1835 | #if EPOLL_SUPPORT | 2367 | #if EPOLL_SUPPORT |
1836 | /** | 2368 | /** |
1837 | * Schedule MHD. This function should be called initially when an | 2369 | * Schedule MHD. This function should be called initially when an |
@@ -1982,6 +2514,7 @@ TALER_FAKEBANK_start2 (uint16_t port, | |||
1982 | } | 2514 | } |
1983 | GNUNET_assert (strlen (currency) < TALER_CURRENCY_LEN); | 2515 | GNUNET_assert (strlen (currency) < TALER_CURRENCY_LEN); |
1984 | h = GNUNET_new (struct TALER_FAKEBANK_Handle); | 2516 | h = GNUNET_new (struct TALER_FAKEBANK_Handle); |
2517 | h->lp_event = -1; | ||
1985 | h->port = port; | 2518 | h->port = port; |
1986 | h->ram_limit = ram_limit; | 2519 | h->ram_limit = ram_limit; |
1987 | h->serial_counter = 0; | 2520 | h->serial_counter = 0; |
@@ -2027,6 +2560,7 @@ TALER_FAKEBANK_start2 (uint16_t port, | |||
2027 | TALER_FAKEBANK_stop (h); | 2560 | TALER_FAKEBANK_stop (h); |
2028 | return NULL; | 2561 | return NULL; |
2029 | } | 2562 | } |
2563 | h->lp_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
2030 | h->currency = GNUNET_strdup (currency); | 2564 | h->currency = GNUNET_strdup (currency); |
2031 | GNUNET_asprintf (&h->my_baseurl, | 2565 | GNUNET_asprintf (&h->my_baseurl, |
2032 | "http://localhost:%u/", | 2566 | "http://localhost:%u/", |
@@ -2061,6 +2595,28 @@ TALER_FAKEBANK_start2 (uint16_t port, | |||
2061 | } | 2595 | } |
2062 | else | 2596 | else |
2063 | { | 2597 | { |
2598 | h->lp_event = eventfd (0, | ||
2599 | EFD_CLOEXEC); | ||
2600 | if (-1 == h->lp_event) | ||
2601 | { | ||
2602 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
2603 | "eventfd"); | ||
2604 | TALER_FAKEBANK_stop (h); | ||
2605 | return NULL; | ||
2606 | } | ||
2607 | if (0 != | ||
2608 | pthread_create (&h->lp_thread, | ||
2609 | NULL, | ||
2610 | &lp_expiration_thread, | ||
2611 | h)) | ||
2612 | { | ||
2613 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
2614 | "pthread_create"); | ||
2615 | GNUNET_break (0 == close (h->lp_event)); | ||
2616 | h->lp_event = -1; | ||
2617 | TALER_FAKEBANK_stop (h); | ||
2618 | return NULL; | ||
2619 | } | ||
2064 | h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG | 2620 | h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG |
2065 | | MHD_USE_AUTO_INTERNAL_THREAD | 2621 | | MHD_USE_AUTO_INTERNAL_THREAD |
2066 | | MHD_ALLOW_SUSPEND_RESUME | 2622 | | MHD_ALLOW_SUSPEND_RESUME |