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