pq_result_helper.c (44788B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file pq/pq_result_helper.c 18 * @brief functions to initialize parameter arrays 19 * @author Christian Grothoff 20 */ 21 #include "taler/platform.h" 22 #include <gnunet/gnunet_util_lib.h> 23 #include "pq_common.h" 24 #include "taler/taler_pq_lib.h" 25 26 27 /** 28 * Extract an amount from a tuple including the currency from a Postgres 29 * database @a result at row @a row. 30 * 31 * @param cls closure; not used 32 * @param result where to extract data from 33 * @param row row to extract data from 34 * @param fname name (or prefix) of the fields to extract from 35 * @param[in,out] dst_size where to store size of result, may be NULL 36 * @param[out] dst where to store the result 37 * @return 38 * #GNUNET_YES if all results could be extracted 39 * #GNUNET_NO if at least one result was NULL 40 * #GNUNET_SYSERR if a result was invalid (non-existing field) 41 */ 42 static enum GNUNET_GenericReturnValue 43 extract_amount_currency_tuple (void *cls, 44 PGresult *result, 45 int row, 46 const char *fname, 47 size_t *dst_size, 48 void *dst) 49 { 50 struct TALER_Amount *r_amount = dst; 51 int col; 52 53 (void) cls; 54 if (sizeof (struct TALER_Amount) != *dst_size) 55 { 56 GNUNET_break (0); 57 return GNUNET_SYSERR; 58 } 59 60 /* Set return value to invalid in case we don't finish */ 61 memset (r_amount, 62 0, 63 sizeof (struct TALER_Amount)); 64 col = PQfnumber (result, 65 fname); 66 if (col < 0) 67 { 68 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 69 "Field `%s' does not exist in result\n", 70 fname); 71 return GNUNET_SYSERR; 72 } 73 if (PQgetisnull (result, 74 row, 75 col)) 76 { 77 return GNUNET_NO; 78 } 79 80 /* Parse the tuple */ 81 { 82 struct TALER_PQ_AmountCurrencyP ap; 83 const char *in; 84 size_t size; 85 86 size = PQgetlength (result, 87 row, 88 col); 89 if ( (size >= sizeof (ap)) || 90 (size <= sizeof (ap) - TALER_CURRENCY_LEN) ) 91 { 92 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 93 "Incorrect size of binary field `%s' (got %zu, expected (%zu-%zu))\n", 94 fname, 95 size, 96 sizeof (ap) - TALER_CURRENCY_LEN, 97 sizeof (ap)); 98 return GNUNET_SYSERR; 99 } 100 101 in = PQgetvalue (result, 102 row, 103 col); 104 memset (&ap.c, 105 0, 106 TALER_CURRENCY_LEN); 107 memcpy (&ap, 108 in, 109 size); 110 if (3 != ntohl (ap.cnt)) 111 { 112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 113 "Incorrect number of elements in tuple-field `%s'\n", 114 fname); 115 return GNUNET_SYSERR; 116 } 117 /* FIXME[oec]: OID-checks? */ 118 119 r_amount->value = GNUNET_ntohll (ap.v); 120 r_amount->fraction = ntohl (ap.f); 121 memcpy (r_amount->currency, 122 ap.c, 123 TALER_CURRENCY_LEN); 124 if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1]) 125 { 126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 127 "Invalid currency (not 0-terminated) in tuple field `%s'\n", 128 fname); 129 /* be sure nobody uses this by accident */ 130 memset (r_amount, 131 0, 132 sizeof (struct TALER_Amount)); 133 return GNUNET_SYSERR; 134 } 135 } 136 137 if (r_amount->value >= TALER_AMOUNT_MAX_VALUE) 138 { 139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 140 "Value in field `%s' exceeds legal range\n", 141 fname); 142 return GNUNET_SYSERR; 143 } 144 if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE) 145 { 146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 147 "Fraction in field `%s' exceeds legal range\n", 148 fname); 149 return GNUNET_SYSERR; 150 } 151 return GNUNET_OK; 152 } 153 154 155 struct GNUNET_PQ_ResultSpec 156 TALER_PQ_result_spec_amount_with_currency (const char *name, 157 struct TALER_Amount *amount) 158 { 159 struct GNUNET_PQ_ResultSpec res = { 160 .conv = &extract_amount_currency_tuple, 161 .dst = (void *) amount, 162 .dst_size = sizeof (*amount), 163 .fname = name 164 }; 165 166 return res; 167 } 168 169 170 /** 171 * Extract an amount from a tuple from a Postgres database @a result at row @a row. 172 * 173 * @param cls closure, a `const char *` giving the currency 174 * @param result where to extract data from 175 * @param row row to extract data from 176 * @param fname name (or prefix) of the fields to extract from 177 * @param[in,out] dst_size where to store size of result, may be NULL 178 * @param[out] dst where to store the result 179 * @return 180 * #GNUNET_YES if all results could be extracted 181 * #GNUNET_NO if at least one result was NULL 182 * #GNUNET_SYSERR if a result was invalid (non-existing field) 183 */ 184 static enum GNUNET_GenericReturnValue 185 extract_amount_tuple (void *cls, 186 PGresult *result, 187 int row, 188 const char *fname, 189 size_t *dst_size, 190 void *dst) 191 { 192 struct TALER_Amount *r_amount = dst; 193 const char *currency = cls; 194 int col; 195 size_t len; 196 197 if (sizeof (struct TALER_Amount) != *dst_size) 198 { 199 GNUNET_break (0); 200 return GNUNET_SYSERR; 201 } 202 203 /* Set return value to invalid in case we don't finish */ 204 memset (r_amount, 205 0, 206 sizeof (struct TALER_Amount)); 207 col = PQfnumber (result, 208 fname); 209 if (col < 0) 210 { 211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 212 "Field `%s' does not exist in result\n", 213 fname); 214 return GNUNET_SYSERR; 215 } 216 if (PQgetisnull (result, 217 row, 218 col)) 219 { 220 return GNUNET_NO; 221 } 222 223 /* Parse the tuple */ 224 { 225 struct TALER_PQ_AmountP ap; 226 const char *in; 227 size_t size; 228 229 size = PQgetlength (result, 230 row, 231 col); 232 in = PQgetvalue (result, 233 row, 234 col); 235 if (sizeof(struct TALER_PQ_AmountNullP) == size) 236 { 237 struct TALER_PQ_AmountNullP apn; 238 239 memcpy (&apn, 240 in, 241 size); 242 if ( (2 == ntohl (apn.cnt)) && 243 (-1 == (int32_t) ntohl (apn.sz_v)) && 244 (-1 == (int32_t) ntohl (apn.sz_f)) ) 245 { 246 /* is NULL! */ 247 return GNUNET_NO; 248 } 249 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 250 "Incorrect size of binary field `%s' and not NULL (got %zu, expected %zu)\n", 251 fname, 252 size, 253 sizeof(ap)); 254 return GNUNET_SYSERR; 255 } 256 if (sizeof(ap) != size) 257 { 258 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 259 "Incorrect size of binary field `%s' (got %zu, expected %zu)\n", 260 fname, 261 size, 262 sizeof(ap)); 263 return GNUNET_SYSERR; 264 } 265 266 memcpy (&ap, 267 in, 268 size); 269 if (2 != ntohl (ap.cnt)) 270 { 271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 272 "Incorrect number of elements in tuple-field `%s'\n", 273 fname); 274 return GNUNET_SYSERR; 275 } 276 /* FIXME[oec]: OID-checks? */ 277 278 r_amount->value = GNUNET_ntohll (ap.v); 279 r_amount->fraction = ntohl (ap.f); 280 } 281 282 if (r_amount->value >= TALER_AMOUNT_MAX_VALUE) 283 { 284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 285 "Value in field `%s' exceeds legal range\n", 286 fname); 287 return GNUNET_SYSERR; 288 } 289 if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE) 290 { 291 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 292 "Fraction in field `%s' exceeds legal range\n", 293 fname); 294 return GNUNET_SYSERR; 295 } 296 297 len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, 298 strlen (currency)); 299 300 GNUNET_memcpy (r_amount->currency, 301 currency, 302 len); 303 return GNUNET_OK; 304 } 305 306 307 struct GNUNET_PQ_ResultSpec 308 TALER_PQ_result_spec_amount (const char *name, 309 const char *currency, 310 struct TALER_Amount *amount) 311 { 312 struct GNUNET_PQ_ResultSpec res = { 313 .conv = &extract_amount_tuple, 314 .cls = (void *) currency, 315 .dst = (void *) amount, 316 .dst_size = sizeof (*amount), 317 .fname = name 318 }; 319 320 return res; 321 } 322 323 324 /** 325 * Extract data from a Postgres database @a result at row @a row. 326 * 327 * @param cls closure 328 * @param result where to extract data from 329 * @param row row to extract data from 330 * @param fname name (or prefix) of the fields to extract from 331 * @param[in,out] dst_size where to store size of result, may be NULL 332 * @param[out] dst where to store the result 333 * @return 334 * #GNUNET_YES if all results could be extracted 335 * #GNUNET_NO if at least one result was NULL 336 * #GNUNET_SYSERR if a result was invalid (non-existing field) 337 */ 338 static enum GNUNET_GenericReturnValue 339 extract_json (void *cls, 340 PGresult *result, 341 int row, 342 const char *fname, 343 size_t *dst_size, 344 void *dst) 345 { 346 json_t **j_dst = dst; 347 const char *res; 348 int fnum; 349 json_error_t json_error; 350 size_t slen; 351 352 (void) cls; 353 (void) dst_size; 354 fnum = PQfnumber (result, 355 fname); 356 if (fnum < 0) 357 { 358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 359 "Field `%s' does not exist in result\n", 360 fname); 361 return GNUNET_SYSERR; 362 } 363 if (PQgetisnull (result, 364 row, 365 fnum)) 366 return GNUNET_NO; 367 slen = PQgetlength (result, 368 row, 369 fnum); 370 res = (const char *) PQgetvalue (result, 371 row, 372 fnum); 373 *j_dst = json_loadb (res, 374 slen, 375 JSON_REJECT_DUPLICATES, 376 &json_error); 377 if (NULL == *j_dst) 378 { 379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 380 "Failed to parse JSON result for field `%s': %s (%s)\n", 381 fname, 382 json_error.text, 383 json_error.source); 384 return GNUNET_SYSERR; 385 } 386 return GNUNET_OK; 387 } 388 389 390 /** 391 * Function called to clean up memory allocated 392 * by a #GNUNET_PQ_ResultConverter. 393 * 394 * @param cls closure 395 * @param rd result data to clean up 396 */ 397 static void 398 clean_json (void *cls, 399 void *rd) 400 { 401 json_t **dst = rd; 402 403 (void) cls; 404 if (NULL != *dst) 405 { 406 json_decref (*dst); 407 *dst = NULL; 408 } 409 } 410 411 412 struct GNUNET_PQ_ResultSpec 413 TALER_PQ_result_spec_json (const char *name, 414 json_t **jp) 415 { 416 struct GNUNET_PQ_ResultSpec res = { 417 .conv = &extract_json, 418 .cleaner = &clean_json, 419 .dst = (void *) jp, 420 .fname = name 421 }; 422 423 return res; 424 } 425 426 427 /** 428 * Extract data from a Postgres database @a result at row @a row. 429 * 430 * @param cls closure 431 * @param result where to extract data from 432 * @param row the row to extract data from 433 * @param fname name (or prefix) of the fields to extract from 434 * @param[in,out] dst_size where to store size of result, may be NULL 435 * @param[out] dst where to store the result 436 * @return 437 * #GNUNET_YES if all results could be extracted 438 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 439 */ 440 static enum GNUNET_GenericReturnValue 441 extract_denom_pub (void *cls, 442 PGresult *result, 443 int row, 444 const char *fname, 445 size_t *dst_size, 446 void *dst) 447 { 448 struct TALER_DenominationPublicKey *pk = dst; 449 struct GNUNET_CRYPTO_BlindSignPublicKey *bpk; 450 size_t len; 451 const char *res; 452 int fnum; 453 uint32_t be[2]; 454 455 (void) cls; 456 (void) dst_size; 457 fnum = PQfnumber (result, 458 fname); 459 if (fnum < 0) 460 { 461 GNUNET_break (0); 462 return GNUNET_SYSERR; 463 } 464 if (PQgetisnull (result, 465 row, 466 fnum)) 467 return GNUNET_NO; 468 469 /* if a field is null, continue but 470 * remember that we now return a different result */ 471 len = PQgetlength (result, 472 row, 473 fnum); 474 res = PQgetvalue (result, 475 row, 476 fnum); 477 if (len < sizeof (be)) 478 { 479 GNUNET_break (0); 480 return GNUNET_SYSERR; 481 } 482 GNUNET_memcpy (be, 483 res, 484 sizeof (be)); 485 res += sizeof (be); 486 len -= sizeof (be); 487 bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 488 bpk->cipher = ntohl (be[0]); 489 bpk->rc = 1; 490 pk->age_mask.bits = ntohl (be[1]); 491 switch (bpk->cipher) 492 { 493 case GNUNET_CRYPTO_BSA_INVALID: 494 break; 495 case GNUNET_CRYPTO_BSA_RSA: 496 bpk->details.rsa_public_key 497 = GNUNET_CRYPTO_rsa_public_key_decode (res, 498 len); 499 if (NULL == bpk->details.rsa_public_key) 500 { 501 GNUNET_break (0); 502 GNUNET_free (bpk); 503 return GNUNET_SYSERR; 504 } 505 pk->bsign_pub_key = bpk; 506 GNUNET_CRYPTO_hash (res, 507 len, 508 &bpk->pub_key_hash); 509 return GNUNET_OK; 510 case GNUNET_CRYPTO_BSA_CS: 511 if (sizeof (bpk->details.cs_public_key) != len) 512 { 513 GNUNET_break (0); 514 GNUNET_free (bpk); 515 return GNUNET_SYSERR; 516 } 517 GNUNET_memcpy (&bpk->details.cs_public_key, 518 res, 519 len); 520 pk->bsign_pub_key = bpk; 521 GNUNET_CRYPTO_hash (res, 522 len, 523 &bpk->pub_key_hash); 524 return GNUNET_OK; 525 } 526 GNUNET_break (0); 527 GNUNET_free (bpk); 528 return GNUNET_SYSERR; 529 } 530 531 532 /** 533 * Function called to clean up memory allocated 534 * by a #GNUNET_PQ_ResultConverter. 535 * 536 * @param cls closure 537 * @param rd result data to clean up 538 */ 539 static void 540 clean_denom_pub (void *cls, 541 void *rd) 542 { 543 struct TALER_DenominationPublicKey *denom_pub = rd; 544 545 (void) cls; 546 TALER_denom_pub_free (denom_pub); 547 } 548 549 550 struct GNUNET_PQ_ResultSpec 551 TALER_PQ_result_spec_denom_pub (const char *name, 552 struct TALER_DenominationPublicKey *denom_pub) 553 { 554 struct GNUNET_PQ_ResultSpec res = { 555 .conv = &extract_denom_pub, 556 .cleaner = &clean_denom_pub, 557 .dst = (void *) denom_pub, 558 .fname = name 559 }; 560 561 return res; 562 } 563 564 565 /** 566 * Extract data from a Postgres database @a result at row @a row. 567 * 568 * @param cls closure 569 * @param result where to extract data from 570 * @param row the row to extract data from 571 * @param fname name (or prefix) of the fields to extract from 572 * @param[in,out] dst_size where to store size of result, may be NULL 573 * @param[out] dst where to store the result 574 * @return 575 * #GNUNET_YES if all results could be extracted 576 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 577 */ 578 static enum GNUNET_GenericReturnValue 579 extract_denom_sig (void *cls, 580 PGresult *result, 581 int row, 582 const char *fname, 583 size_t *dst_size, 584 void *dst) 585 { 586 struct TALER_DenominationSignature *sig = dst; 587 struct GNUNET_CRYPTO_UnblindedSignature *ubs; 588 size_t len; 589 const char *res; 590 int fnum; 591 uint32_t be[2]; 592 593 (void) cls; 594 (void) dst_size; 595 fnum = PQfnumber (result, 596 fname); 597 if (fnum < 0) 598 { 599 GNUNET_break (0); 600 return GNUNET_SYSERR; 601 } 602 if (PQgetisnull (result, 603 row, 604 fnum)) 605 return GNUNET_NO; 606 607 /* if a field is null, continue but 608 * remember that we now return a different result */ 609 len = PQgetlength (result, 610 row, 611 fnum); 612 res = PQgetvalue (result, 613 row, 614 fnum); 615 if (len < sizeof (be)) 616 { 617 GNUNET_break (0); 618 return GNUNET_SYSERR; 619 } 620 GNUNET_memcpy (&be, 621 res, 622 sizeof (be)); 623 if (0x00 != ntohl (be[1])) 624 { 625 GNUNET_break (0); 626 return GNUNET_SYSERR; 627 } 628 res += sizeof (be); 629 len -= sizeof (be); 630 ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature); 631 ubs->rc = 1; 632 ubs->cipher = ntohl (be[0]); 633 switch (ubs->cipher) 634 { 635 case GNUNET_CRYPTO_BSA_INVALID: 636 break; 637 case GNUNET_CRYPTO_BSA_RSA: 638 ubs->details.rsa_signature 639 = GNUNET_CRYPTO_rsa_signature_decode (res, 640 len); 641 if (NULL == ubs->details.rsa_signature) 642 { 643 GNUNET_break (0); 644 GNUNET_free (ubs); 645 return GNUNET_SYSERR; 646 } 647 sig->unblinded_sig = ubs; 648 return GNUNET_OK; 649 case GNUNET_CRYPTO_BSA_CS: 650 if (sizeof (ubs->details.cs_signature) != len) 651 { 652 GNUNET_break (0); 653 GNUNET_free (ubs); 654 return GNUNET_SYSERR; 655 } 656 GNUNET_memcpy (&ubs->details.cs_signature, 657 res, 658 len); 659 sig->unblinded_sig = ubs; 660 return GNUNET_OK; 661 } 662 GNUNET_break (0); 663 GNUNET_free (ubs); 664 return GNUNET_SYSERR; 665 } 666 667 668 /** 669 * Function called to clean up memory allocated 670 * by a #GNUNET_PQ_ResultConverter. 671 * 672 * @param cls closure 673 * @param rd result data to clean up 674 */ 675 static void 676 clean_denom_sig (void *cls, 677 void *rd) 678 { 679 struct TALER_DenominationSignature *denom_sig = rd; 680 681 (void) cls; 682 TALER_denom_sig_free (denom_sig); 683 } 684 685 686 struct GNUNET_PQ_ResultSpec 687 TALER_PQ_result_spec_denom_sig (const char *name, 688 struct TALER_DenominationSignature *denom_sig) 689 { 690 struct GNUNET_PQ_ResultSpec res = { 691 .conv = &extract_denom_sig, 692 .cleaner = &clean_denom_sig, 693 .dst = (void *) denom_sig, 694 .fname = name 695 }; 696 697 return res; 698 } 699 700 701 /** 702 * Extract data from a Postgres database @a result at row @a row. 703 * 704 * @param cls closure 705 * @param result where to extract data from 706 * @param row the row to extract data from 707 * @param fname name (or prefix) of the fields to extract from 708 * @param[in,out] dst_size where to store size of result, may be NULL 709 * @param[out] dst where to store the result 710 * @return 711 * #GNUNET_YES if all results could be extracted 712 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 713 */ 714 static enum GNUNET_GenericReturnValue 715 extract_blinded_denom_sig (void *cls, 716 PGresult *result, 717 int row, 718 const char *fname, 719 size_t *dst_size, 720 void *dst) 721 { 722 struct TALER_BlindedDenominationSignature *sig = dst; 723 struct GNUNET_CRYPTO_BlindedSignature *bs; 724 size_t len; 725 const char *res; 726 int fnum; 727 uint32_t be[2]; 728 729 (void) cls; 730 (void) dst_size; 731 fnum = PQfnumber (result, 732 fname); 733 if (fnum < 0) 734 { 735 GNUNET_break (0); 736 return GNUNET_SYSERR; 737 } 738 if (PQgetisnull (result, 739 row, 740 fnum)) 741 return GNUNET_NO; 742 743 /* if a field is null, continue but 744 * remember that we now return a different result */ 745 len = PQgetlength (result, 746 row, 747 fnum); 748 res = PQgetvalue (result, 749 row, 750 fnum); 751 if (len < sizeof (be)) 752 { 753 GNUNET_break (0); 754 return GNUNET_SYSERR; 755 } 756 GNUNET_memcpy (&be, 757 res, 758 sizeof (be)); 759 if (0x01 != ntohl (be[1])) /* magic marker: blinded */ 760 { 761 GNUNET_break (0); 762 return GNUNET_SYSERR; 763 } 764 res += sizeof (be); 765 len -= sizeof (be); 766 bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 767 bs->rc = 1; 768 bs->cipher = ntohl (be[0]); 769 switch (bs->cipher) 770 { 771 case GNUNET_CRYPTO_BSA_INVALID: 772 break; 773 case GNUNET_CRYPTO_BSA_RSA: 774 bs->details.blinded_rsa_signature 775 = GNUNET_CRYPTO_rsa_signature_decode (res, 776 len); 777 if (NULL == bs->details.blinded_rsa_signature) 778 { 779 GNUNET_break (0); 780 GNUNET_free (bs); 781 return GNUNET_SYSERR; 782 } 783 sig->blinded_sig = bs; 784 return GNUNET_OK; 785 case GNUNET_CRYPTO_BSA_CS: 786 if (sizeof (bs->details.blinded_cs_answer) != len) 787 { 788 GNUNET_break (0); 789 GNUNET_free (bs); 790 return GNUNET_SYSERR; 791 } 792 GNUNET_memcpy (&bs->details.blinded_cs_answer, 793 res, 794 len); 795 sig->blinded_sig = bs; 796 return GNUNET_OK; 797 } 798 GNUNET_break (0); 799 GNUNET_free (bs); 800 return GNUNET_SYSERR; 801 } 802 803 804 /** 805 * Function called to clean up memory allocated 806 * by a #GNUNET_PQ_ResultConverter. 807 * 808 * @param cls closure 809 * @param rd result data to clean up 810 */ 811 static void 812 clean_blinded_denom_sig (void *cls, 813 void *rd) 814 { 815 struct TALER_BlindedDenominationSignature *denom_sig = rd; 816 817 (void) cls; 818 TALER_blinded_denom_sig_free (denom_sig); 819 } 820 821 822 struct GNUNET_PQ_ResultSpec 823 TALER_PQ_result_spec_blinded_denom_sig ( 824 const char *name, 825 struct TALER_BlindedDenominationSignature *denom_sig) 826 { 827 // FIXME: use GNUNET_PQ_result_spec_blinded_sig() 828 struct GNUNET_PQ_ResultSpec res = { 829 .conv = &extract_blinded_denom_sig, 830 .cleaner = &clean_blinded_denom_sig, 831 .dst = (void *) denom_sig, 832 .fname = name 833 }; 834 835 return res; 836 } 837 838 839 /** 840 * Extract data from a Postgres database @a result at row @a row. 841 * 842 * @param cls closure 843 * @param result where to extract data from 844 * @param row the row to extract data from 845 * @param fname name (or prefix) of the fields to extract from 846 * @param[in,out] dst_size where to store size of result, may be NULL 847 * @param[out] dst where to store the result 848 * @return 849 * #GNUNET_YES if all results could be extracted 850 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 851 */ 852 static enum GNUNET_GenericReturnValue 853 extract_blinded_planchet (void *cls, 854 PGresult *result, 855 int row, 856 const char *fname, 857 size_t *dst_size, 858 void *dst) 859 { 860 struct TALER_BlindedPlanchet *bp = dst; 861 struct GNUNET_CRYPTO_BlindedMessage *bm; 862 size_t len; 863 const char *res; 864 int fnum; 865 uint32_t be[2]; 866 867 (void) cls; 868 (void) dst_size; 869 fnum = PQfnumber (result, 870 fname); 871 if (fnum < 0) 872 { 873 GNUNET_break (0); 874 return GNUNET_SYSERR; 875 } 876 if (PQgetisnull (result, 877 row, 878 fnum)) 879 return GNUNET_NO; 880 881 /* if a field is null, continue but 882 * remember that we now return a different result */ 883 len = PQgetlength (result, 884 row, 885 fnum); 886 res = PQgetvalue (result, 887 row, 888 fnum); 889 if (len < sizeof (be)) 890 { 891 GNUNET_break (0); 892 return GNUNET_SYSERR; 893 } 894 GNUNET_memcpy (&be, 895 res, 896 sizeof (be)); 897 if (0x0100 != ntohl (be[1])) /* magic marker: blinded */ 898 { 899 GNUNET_break (0); 900 return GNUNET_SYSERR; 901 } 902 res += sizeof (be); 903 len -= sizeof (be); 904 bm = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); 905 bm->rc = 1; 906 bm->cipher = ntohl (be[0]); 907 switch (bm->cipher) 908 { 909 case GNUNET_CRYPTO_BSA_INVALID: 910 break; 911 case GNUNET_CRYPTO_BSA_RSA: 912 bm->details.rsa_blinded_message.blinded_msg_size 913 = len; 914 bm->details.rsa_blinded_message.blinded_msg 915 = GNUNET_memdup (res, 916 len); 917 bp->blinded_message = bm; 918 return GNUNET_OK; 919 case GNUNET_CRYPTO_BSA_CS: 920 if (sizeof (bm->details.cs_blinded_message) != len) 921 { 922 GNUNET_break (0); 923 GNUNET_free (bm); 924 return GNUNET_SYSERR; 925 } 926 GNUNET_memcpy (&bm->details.cs_blinded_message, 927 res, 928 len); 929 bp->blinded_message = bm; 930 return GNUNET_OK; 931 } 932 GNUNET_break (0); 933 GNUNET_free (bm); 934 return GNUNET_SYSERR; 935 } 936 937 938 /** 939 * Function called to clean up memory allocated 940 * by a #GNUNET_PQ_ResultConverter. 941 * 942 * @param cls closure 943 * @param rd result data to clean up 944 */ 945 static void 946 clean_blinded_planchet (void *cls, 947 void *rd) 948 { 949 struct TALER_BlindedPlanchet *bp = rd; 950 951 (void) cls; 952 TALER_blinded_planchet_free (bp); 953 } 954 955 956 struct GNUNET_PQ_ResultSpec 957 TALER_PQ_result_spec_blinded_planchet ( 958 const char *name, 959 struct TALER_BlindedPlanchet *bp) 960 { 961 struct GNUNET_PQ_ResultSpec res = { 962 .conv = &extract_blinded_planchet, 963 .cleaner = &clean_blinded_planchet, 964 .dst = (void *) bp, 965 .fname = name 966 }; 967 968 return res; 969 } 970 971 972 /** 973 * Extract data from a Postgres database @a result at row @a row. 974 * 975 * @param cls closure 976 * @param result where to extract data from 977 * @param row row to extract data from 978 * @param fname name (or prefix) of the fields to extract from 979 * @param[in,out] dst_size where to store size of result, may be NULL 980 * @param[out] dst where to store the result 981 * @return 982 * #GNUNET_YES if all results could be extracted 983 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 984 */ 985 static enum GNUNET_GenericReturnValue 986 extract_exchange_withdraw_values (void *cls, 987 PGresult *result, 988 int row, 989 const char *fname, 990 size_t *dst_size, 991 void *dst) 992 { 993 struct TALER_ExchangeBlindingValues *alg_values = dst; 994 struct GNUNET_CRYPTO_BlindingInputValues *bi; 995 size_t len; 996 const char *res; 997 int fnum; 998 uint32_t be[2]; 999 1000 (void) cls; 1001 (void) dst_size; 1002 fnum = PQfnumber (result, 1003 fname); 1004 if (fnum < 0) 1005 { 1006 GNUNET_break (0); 1007 return GNUNET_SYSERR; 1008 } 1009 if (PQgetisnull (result, 1010 row, 1011 fnum)) 1012 return GNUNET_NO; 1013 1014 /* if a field is null, continue but 1015 * remember that we now return a different result */ 1016 len = PQgetlength (result, 1017 row, 1018 fnum); 1019 res = PQgetvalue (result, 1020 row, 1021 fnum); 1022 if (len < sizeof (be)) 1023 { 1024 GNUNET_break (0); 1025 return GNUNET_SYSERR; 1026 } 1027 GNUNET_memcpy (&be, 1028 res, 1029 sizeof (be)); 1030 if (0x010000 != ntohl (be[1])) /* magic marker: EWV */ 1031 { 1032 GNUNET_break (0); 1033 return GNUNET_SYSERR; 1034 } 1035 res += sizeof (be); 1036 len -= sizeof (be); 1037 bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues); 1038 bi->rc = 1; 1039 bi->cipher = ntohl (be[0]); 1040 switch (bi->cipher) 1041 { 1042 case GNUNET_CRYPTO_BSA_INVALID: 1043 break; 1044 case GNUNET_CRYPTO_BSA_RSA: 1045 if (0 != len) 1046 { 1047 GNUNET_break (0); 1048 GNUNET_free (bi); 1049 return GNUNET_SYSERR; 1050 } 1051 alg_values->blinding_inputs = bi; 1052 return GNUNET_OK; 1053 case GNUNET_CRYPTO_BSA_CS: 1054 if (sizeof (bi->details.cs_values) != len) 1055 { 1056 GNUNET_break (0); 1057 GNUNET_free (bi); 1058 return GNUNET_SYSERR; 1059 } 1060 GNUNET_memcpy (&bi->details.cs_values, 1061 res, 1062 len); 1063 alg_values->blinding_inputs = bi; 1064 return GNUNET_OK; 1065 } 1066 GNUNET_break (0); 1067 GNUNET_free (bi); 1068 return GNUNET_SYSERR; 1069 } 1070 1071 1072 struct GNUNET_PQ_ResultSpec 1073 TALER_PQ_result_spec_exchange_withdraw_values ( 1074 const char *name, 1075 struct TALER_ExchangeBlindingValues *ewv) 1076 { 1077 struct GNUNET_PQ_ResultSpec res = { 1078 .conv = &extract_exchange_withdraw_values, 1079 .dst = (void *) ewv, 1080 .fname = name 1081 }; 1082 1083 return res; 1084 } 1085 1086 1087 /** 1088 * Closure for the array result specifications. Contains type information 1089 * for the generic parser extract_array_generic and out-pointers for the results. 1090 */ 1091 struct ArrayResultCls 1092 { 1093 /** 1094 * Oid of the expected type, must match the oid in the header of the PQResult struct 1095 */ 1096 Oid oid; 1097 1098 /** 1099 * Target type 1100 */ 1101 enum TALER_PQ_ArrayType typ; 1102 1103 /** 1104 * If not 0, defines the expected size of each entry 1105 */ 1106 size_t same_size; 1107 1108 /** 1109 * Out-pointer to write the number of elements in the array 1110 */ 1111 size_t *num; 1112 1113 /** 1114 * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0, 1115 * allocate and put the array of @a num sizes here. NULL otherwise 1116 */ 1117 size_t **sizes; 1118 1119 /** 1120 * DB_connection, needed for OID-lookup for composite types 1121 */ 1122 const struct GNUNET_PQ_Context *db; 1123 1124 /** 1125 * Currency information for amount composites 1126 */ 1127 char currency[TALER_CURRENCY_LEN]; 1128 }; 1129 1130 1131 /** 1132 * Extract data from a Postgres database @a result as array of a specific type 1133 * from row @a row. The type information and optionally additional 1134 * out-parameters are given in @a cls which is of type array_result_cls. 1135 * 1136 * @param cls closure of type array_result_cls 1137 * @param result where to extract data from 1138 * @param row row to extract data from 1139 * @param fname name (or prefix) of the fields to extract from 1140 * @param[in,out] dst_size where to store size of result, may be NULL 1141 * @param[out] dst where to store the result 1142 * @return 1143 * #GNUNET_YES if all results could be extracted 1144 * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) 1145 */ 1146 static enum GNUNET_GenericReturnValue 1147 extract_array_generic ( 1148 void *cls, 1149 PGresult *result, 1150 int row, 1151 const char *fname, 1152 size_t *dst_size, 1153 void *dst) 1154 { 1155 const struct ArrayResultCls *info = cls; 1156 int data_sz; 1157 char *data; 1158 void *out = NULL; 1159 struct GNUNET_PQ_ArrayHeader_P header; 1160 int col_num; 1161 1162 GNUNET_assert (NULL != dst); 1163 *((void **) dst) = NULL; 1164 1165 #define FAIL_IF(cond) \ 1166 do { \ 1167 if ((cond)) \ 1168 { \ 1169 GNUNET_break (! (cond)); \ 1170 goto FAIL; \ 1171 } \ 1172 } while (0) 1173 1174 col_num = PQfnumber (result, fname); 1175 FAIL_IF (0 > col_num); 1176 1177 if (PQgetisnull (result, row, col_num)) 1178 { 1179 return GNUNET_NO; 1180 } 1181 1182 data_sz = PQgetlength (result, row, col_num); 1183 FAIL_IF (0 > data_sz); 1184 FAIL_IF (sizeof(header) > (size_t) data_sz); 1185 1186 data = PQgetvalue (result, row, col_num); 1187 FAIL_IF (NULL == data); 1188 1189 { 1190 struct GNUNET_PQ_ArrayHeader_P *h = 1191 (struct GNUNET_PQ_ArrayHeader_P *) data; 1192 1193 header.ndim = ntohl (h->ndim); 1194 header.has_null = ntohl (h->has_null); 1195 header.oid = ntohl (h->oid); 1196 header.dim = ntohl (h->dim); 1197 header.lbound = ntohl (h->lbound); 1198 1199 FAIL_IF (1 != header.ndim); 1200 FAIL_IF (INT_MAX <= header.dim); 1201 FAIL_IF (0 != header.has_null); 1202 FAIL_IF (1 != header.lbound); 1203 FAIL_IF (info->oid != header.oid); 1204 } 1205 1206 if (NULL != info->num) 1207 *info->num = header.dim; 1208 1209 { 1210 char *in = data + sizeof(header); 1211 1212 switch (info->typ) 1213 { 1214 case TALER_PQ_array_of_amount: 1215 { 1216 struct TALER_Amount *amounts; 1217 if (NULL != dst_size) 1218 *dst_size = sizeof(struct TALER_Amount) * (header.dim); 1219 1220 amounts = GNUNET_new_array (header.dim, 1221 struct TALER_Amount); 1222 *((void **) dst) = amounts; 1223 1224 for (uint32_t i = 0; i < header.dim; i++) 1225 { 1226 struct TALER_PQ_AmountP ap; 1227 struct TALER_Amount *amount = &amounts[i]; 1228 uint32_t val; 1229 size_t sz; 1230 1231 GNUNET_memcpy (&val, 1232 in, 1233 sizeof(val)); 1234 sz = ntohl (val); 1235 in += sizeof(val); 1236 1237 /* total size for this array-entry */ 1238 FAIL_IF (sizeof(ap) != sz); 1239 1240 GNUNET_memcpy (&ap, 1241 in, 1242 sz); 1243 FAIL_IF (2 != ntohl (ap.cnt)); 1244 1245 amount->value = GNUNET_ntohll (ap.v); 1246 amount->fraction = ntohl (ap.f); 1247 GNUNET_memcpy (amount->currency, 1248 info->currency, 1249 TALER_CURRENCY_LEN); 1250 1251 in += sizeof(struct TALER_PQ_AmountP); 1252 } 1253 return GNUNET_OK; 1254 } 1255 case TALER_PQ_array_of_amount_currency: 1256 { 1257 struct TALER_Amount *amounts; 1258 if (NULL != dst_size) 1259 *dst_size = sizeof(struct TALER_Amount) * (header.dim); 1260 1261 amounts = GNUNET_new_array (header.dim, 1262 struct TALER_Amount); 1263 *((void **) dst) = amounts; 1264 1265 for (uint32_t i = 0; i < header.dim; i++) 1266 { 1267 struct TALER_PQ_AmountCurrencyP ap; 1268 struct TALER_Amount *amount = &amounts[i]; 1269 uint32_t val; 1270 size_t sz; 1271 1272 GNUNET_memcpy (&val, 1273 in, 1274 sizeof(val)); 1275 sz = ntohl (val); 1276 in += sizeof(val); 1277 1278 FAIL_IF ( (sz >= sizeof(ap)) || 1279 (sz <= sizeof(ap) - TALER_CURRENCY_LEN) ); 1280 1281 memset (&ap, 1282 0, 1283 sizeof(ap)); 1284 GNUNET_memcpy (&ap, 1285 in, 1286 sz); 1287 FAIL_IF (3 != ntohl (ap.cnt)); 1288 1289 amount->value = GNUNET_ntohll (ap.v); 1290 amount->fraction = ntohl (ap.f); 1291 GNUNET_memcpy (amount->currency, 1292 ap.c, 1293 TALER_CURRENCY_LEN); 1294 1295 FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]); 1296 FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE); 1297 FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE); 1298 1299 in += sz; 1300 } 1301 return GNUNET_OK; 1302 } 1303 case TALER_PQ_array_of_denom_hash: 1304 if (NULL != dst_size) 1305 *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim); 1306 out = GNUNET_new_array (header.dim, 1307 struct TALER_DenominationHashP); 1308 *((void **) dst) = out; 1309 for (uint32_t i = 0; i < header.dim; i++) 1310 { 1311 uint32_t val; 1312 size_t sz; 1313 1314 GNUNET_memcpy (&val, 1315 in, 1316 sizeof(val)); 1317 sz = ntohl (val); 1318 FAIL_IF (sz != sizeof(struct TALER_DenominationHashP)); 1319 in += sizeof(uint32_t); 1320 *(struct TALER_DenominationHashP *) out = 1321 *(struct TALER_DenominationHashP *) in; 1322 in += sz; 1323 out += sz; 1324 } 1325 return GNUNET_OK; 1326 1327 case TALER_PQ_array_of_hash_code: 1328 if (NULL != dst_size) 1329 *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim); 1330 out = GNUNET_new_array (header.dim, 1331 struct GNUNET_HashCode); 1332 *((void **) dst) = out; 1333 for (uint32_t i = 0; i < header.dim; i++) 1334 { 1335 uint32_t val; 1336 size_t sz; 1337 1338 GNUNET_memcpy (&val, 1339 in, 1340 sizeof(val)); 1341 sz = ntohl (val); 1342 FAIL_IF (sz != sizeof(struct GNUNET_HashCode)); 1343 in += sizeof(uint32_t); 1344 *(struct GNUNET_HashCode *) out = 1345 *(struct GNUNET_HashCode *) in; 1346 in += sz; 1347 out += sz; 1348 } 1349 return GNUNET_OK; 1350 1351 case TALER_PQ_array_of_blinded_coin_hash: 1352 if (NULL != dst_size) 1353 *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim); 1354 out = GNUNET_new_array (header.dim, 1355 struct TALER_BlindedCoinHashP); 1356 *((void **) dst) = out; 1357 for (uint32_t i = 0; i < header.dim; i++) 1358 { 1359 uint32_t val; 1360 size_t sz; 1361 1362 GNUNET_memcpy (&val, 1363 in, 1364 sizeof(val)); 1365 sz = ntohl (val); 1366 FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP)); 1367 in += sizeof(uint32_t); 1368 *(struct TALER_BlindedCoinHashP *) out = 1369 *(struct TALER_BlindedCoinHashP *) in; 1370 in += sz; 1371 out += sz; 1372 } 1373 return GNUNET_OK; 1374 1375 case TALER_PQ_array_of_cs_r_pub: 1376 if (NULL != dst_size) 1377 *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim); 1378 out = GNUNET_new_array (header.dim, 1379 struct GNUNET_CRYPTO_CSPublicRPairP); 1380 *((void **) dst) = out; 1381 for (uint32_t i = 0; i < header.dim; i++) 1382 { 1383 uint32_t val; 1384 size_t sz; 1385 1386 GNUNET_memcpy (&val, 1387 in, 1388 sizeof(val)); 1389 sz = ntohl (val); 1390 FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP)); 1391 in += sizeof(uint32_t); 1392 *(struct GNUNET_CRYPTO_CSPublicRPairP *) out = 1393 *(struct GNUNET_CRYPTO_CSPublicRPairP *) in; 1394 in += sz; 1395 out += sz; 1396 } 1397 return GNUNET_OK; 1398 1399 case TALER_PQ_array_of_blinded_denom_sig: 1400 { 1401 struct TALER_BlindedDenominationSignature *denom_sigs; 1402 if (0 == header.dim) 1403 { 1404 if (NULL != dst_size) 1405 *dst_size = 0; 1406 break; 1407 } 1408 1409 denom_sigs = GNUNET_new_array (header.dim, 1410 struct TALER_BlindedDenominationSignature); 1411 *((void **) dst) = denom_sigs; 1412 1413 /* copy data */ 1414 for (uint32_t i = 0; i < header.dim; i++) 1415 { 1416 struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i]; 1417 struct GNUNET_CRYPTO_BlindedSignature *bs; 1418 uint32_t be[2]; 1419 uint32_t val; 1420 size_t sz; 1421 1422 GNUNET_memcpy (&val, 1423 in, 1424 sizeof(val)); 1425 sz = ntohl (val); 1426 FAIL_IF (sizeof(be) > sz); 1427 1428 in += sizeof(val); 1429 GNUNET_memcpy (&be, 1430 in, 1431 sizeof(be)); 1432 FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */ 1433 1434 in += sizeof(be); 1435 sz -= sizeof(be); 1436 bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 1437 bs->cipher = ntohl (be[0]); 1438 bs->rc = 1; 1439 switch (bs->cipher) 1440 { 1441 case GNUNET_CRYPTO_BSA_RSA: 1442 bs->details.blinded_rsa_signature 1443 = GNUNET_CRYPTO_rsa_signature_decode (in, 1444 sz); 1445 if (NULL == bs->details.blinded_rsa_signature) 1446 { 1447 GNUNET_free (bs); 1448 FAIL_IF (true); 1449 } 1450 break; 1451 case GNUNET_CRYPTO_BSA_CS: 1452 if (sizeof(bs->details.blinded_cs_answer) != sz) 1453 { 1454 GNUNET_free (bs); 1455 FAIL_IF (true); 1456 } 1457 GNUNET_memcpy (&bs->details.blinded_cs_answer, 1458 in, 1459 sz); 1460 break; 1461 default: 1462 GNUNET_free (bs); 1463 FAIL_IF (true); 1464 } 1465 denom_sig->blinded_sig = bs; 1466 in += sz; 1467 } 1468 return GNUNET_OK; 1469 } 1470 default: 1471 FAIL_IF (true); 1472 } 1473 } 1474 FAIL: 1475 GNUNET_free (*(void **) dst); 1476 return GNUNET_SYSERR; 1477 #undef FAIL_IF 1478 } 1479 1480 1481 /** 1482 * Cleanup of the data and closure of an array spec. 1483 */ 1484 static void 1485 array_cleanup (void *cls, 1486 void *rd) 1487 { 1488 struct ArrayResultCls *info = cls; 1489 void **dst = rd; 1490 1491 if ( (0 == info->same_size) && 1492 (NULL != info->sizes) ) 1493 GNUNET_free (*(info->sizes)); 1494 1495 /* Clean up signatures, if applicable */ 1496 if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) && 1497 (NULL != *dst)) 1498 { 1499 struct TALER_BlindedDenominationSignature *denom_sigs = *dst; 1500 1501 GNUNET_assert (NULL != info->num); 1502 for (size_t i = 0; i < *info->num; i++) 1503 GNUNET_free (denom_sigs[i].blinded_sig); 1504 } 1505 GNUNET_free (info); 1506 GNUNET_free (*dst); 1507 *dst = NULL; 1508 } 1509 1510 1511 struct GNUNET_PQ_ResultSpec 1512 TALER_PQ_result_spec_array_blinded_denom_sig ( 1513 struct GNUNET_PQ_Context *db, 1514 const char *name, 1515 size_t *num, 1516 struct TALER_BlindedDenominationSignature **denom_sigs) 1517 { 1518 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1519 1520 info->num = num; 1521 info->typ = TALER_PQ_array_of_blinded_denom_sig; 1522 GNUNET_assert (GNUNET_OK == 1523 GNUNET_PQ_get_oid_by_name (db, 1524 "bytea", 1525 &info->oid)); 1526 { 1527 struct GNUNET_PQ_ResultSpec res = { 1528 .conv = extract_array_generic, 1529 .cleaner = &array_cleanup, 1530 .dst = (void *) denom_sigs, 1531 .fname = name, 1532 .cls = info 1533 }; 1534 1535 return res; 1536 } 1537 } 1538 1539 1540 struct GNUNET_PQ_ResultSpec 1541 TALER_PQ_result_spec_array_blinded_coin_hash ( 1542 struct GNUNET_PQ_Context *db, 1543 const char *name, 1544 size_t *num, 1545 struct TALER_BlindedCoinHashP **h_coin_evs) 1546 { 1547 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1548 1549 info->num = num; 1550 info->typ = TALER_PQ_array_of_blinded_coin_hash; 1551 GNUNET_assert (GNUNET_OK == 1552 GNUNET_PQ_get_oid_by_name (db, 1553 "bytea", 1554 &info->oid)); 1555 { 1556 struct GNUNET_PQ_ResultSpec res = { 1557 .conv = extract_array_generic, 1558 .cleaner = &array_cleanup, 1559 .dst = (void *) h_coin_evs, 1560 .fname = name, 1561 .cls = info 1562 }; 1563 1564 return res; 1565 } 1566 } 1567 1568 1569 struct GNUNET_PQ_ResultSpec 1570 TALER_PQ_result_spec_array_denom_hash ( 1571 struct GNUNET_PQ_Context *db, 1572 const char *name, 1573 size_t *num, 1574 struct TALER_DenominationHashP **denom_hs) 1575 { 1576 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1577 1578 info->num = num; 1579 info->typ = TALER_PQ_array_of_denom_hash; 1580 GNUNET_assert (GNUNET_OK == 1581 GNUNET_PQ_get_oid_by_name (db, 1582 "bytea", 1583 &info->oid)); 1584 { 1585 struct GNUNET_PQ_ResultSpec res = { 1586 .conv = extract_array_generic, 1587 .cleaner = &array_cleanup, 1588 .dst = (void *) denom_hs, 1589 .fname = name, 1590 .cls = info 1591 }; 1592 1593 return res; 1594 } 1595 } 1596 1597 1598 struct GNUNET_PQ_ResultSpec 1599 TALER_PQ_result_spec_array_amount ( 1600 struct GNUNET_PQ_Context *db, 1601 const char *name, 1602 const char *currency, 1603 size_t *num, 1604 struct TALER_Amount **amounts) 1605 { 1606 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1607 1608 info->num = num; 1609 info->typ = TALER_PQ_array_of_amount; 1610 info->db = db; 1611 GNUNET_assert (GNUNET_OK == 1612 GNUNET_PQ_get_oid_by_name (db, 1613 "taler_amount", 1614 &info->oid)); 1615 1616 { 1617 size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1, 1618 strlen (currency)); 1619 GNUNET_memcpy (&info->currency, 1620 currency, 1621 clen); 1622 } 1623 { 1624 struct GNUNET_PQ_ResultSpec res = { 1625 .conv = extract_array_generic, 1626 .cleaner = &array_cleanup, 1627 .dst = (void *) amounts, 1628 .fname = name, 1629 .cls = info, 1630 }; 1631 1632 return res; 1633 } 1634 } 1635 1636 1637 struct GNUNET_PQ_ResultSpec 1638 TALER_PQ_result_spec_array_amount_with_currency ( 1639 struct GNUNET_PQ_Context *db, 1640 const char *name, 1641 size_t *num, 1642 struct TALER_Amount **amounts) 1643 { 1644 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1645 1646 info->num = num; 1647 info->typ = TALER_PQ_array_of_amount_currency; 1648 info->db = db; 1649 GNUNET_assert (GNUNET_OK == 1650 GNUNET_PQ_get_oid_by_name (db, 1651 "taler_amount_currency", 1652 &info->oid)); 1653 1654 { 1655 struct GNUNET_PQ_ResultSpec res = { 1656 .conv = extract_array_generic, 1657 .cleaner = &array_cleanup, 1658 .dst = (void *) amounts, 1659 .fname = name, 1660 .cls = info, 1661 }; 1662 1663 return res; 1664 } 1665 } 1666 1667 1668 struct GNUNET_PQ_ResultSpec 1669 TALER_PQ_result_spec_array_hash_code ( 1670 struct GNUNET_PQ_Context *db, 1671 const char *name, 1672 size_t *num, 1673 struct GNUNET_HashCode **hashes) 1674 { 1675 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1676 1677 info->num = num; 1678 info->typ = TALER_PQ_array_of_hash_code; 1679 info->db = db; 1680 GNUNET_assert (GNUNET_OK == 1681 GNUNET_PQ_get_oid_by_name (db, 1682 "gnunet_hashcode", 1683 &info->oid)); 1684 { 1685 struct GNUNET_PQ_ResultSpec res = { 1686 .conv = extract_array_generic, 1687 .cleaner = &array_cleanup, 1688 .dst = (void *) hashes, 1689 .fname = name, 1690 .cls = info, 1691 }; 1692 1693 return res; 1694 } 1695 } 1696 1697 1698 struct GNUNET_PQ_ResultSpec 1699 TALER_PQ_result_spec_array_cs_r_pub ( 1700 struct GNUNET_PQ_Context *db, 1701 const char *name, 1702 size_t *num, 1703 struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs) 1704 { 1705 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1706 1707 info->num = num; 1708 info->typ = TALER_PQ_array_of_cs_r_pub; 1709 GNUNET_assert (GNUNET_OK == 1710 GNUNET_PQ_get_oid_by_name (db, 1711 "bytea", 1712 &info->oid)); 1713 { 1714 struct GNUNET_PQ_ResultSpec res = { 1715 .conv = extract_array_generic, 1716 .cleaner = &array_cleanup, 1717 .dst = (void *) cs_r_pubs, 1718 .fname = name, 1719 .cls = info 1720 }; 1721 1722 return res; 1723 } 1724 } 1725 1726 1727 /* end of pq_result_helper.c */