pq_result_helper.c (45283B)
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 <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 1185 /* Report if this field is empty */ 1186 if (0 == (size_t) data_sz) 1187 return GNUNET_NO; 1188 1189 data = PQgetvalue (result, row, col_num); 1190 1191 if (sizeof(header) > (size_t) data_sz) 1192 { 1193 uint32_t ndim; 1194 1195 /* data_sz is shorter than header if the 1196 array length is 0, in which case ndim is 0! */ 1197 FAIL_IF (sizeof(uint32_t) > (size_t) data_sz); 1198 memcpy (&ndim, 1199 data, 1200 sizeof (ndim)); 1201 FAIL_IF (0 != ndim); 1202 *info->num = 0; 1203 return GNUNET_OK; 1204 } 1205 FAIL_IF (sizeof(header) > (size_t) data_sz); 1206 FAIL_IF (NULL == data); 1207 1208 { 1209 struct GNUNET_PQ_ArrayHeader_P *h = 1210 (struct GNUNET_PQ_ArrayHeader_P *) data; 1211 1212 header.ndim = ntohl (h->ndim); 1213 header.has_null = ntohl (h->has_null); 1214 header.oid = ntohl (h->oid); 1215 header.dim = ntohl (h->dim); 1216 header.lbound = ntohl (h->lbound); 1217 1218 FAIL_IF (1 != header.ndim); 1219 FAIL_IF (INT_MAX <= header.dim); 1220 FAIL_IF (0 != header.has_null); 1221 FAIL_IF (1 != header.lbound); 1222 FAIL_IF (info->oid != header.oid); 1223 } 1224 1225 if (NULL != info->num) 1226 *info->num = header.dim; 1227 1228 { 1229 char *in = data + sizeof(header); 1230 1231 switch (info->typ) 1232 { 1233 case TALER_PQ_array_of_amount: 1234 { 1235 struct TALER_Amount *amounts; 1236 if (NULL != dst_size) 1237 *dst_size = sizeof(struct TALER_Amount) * (header.dim); 1238 1239 amounts = GNUNET_new_array (header.dim, 1240 struct TALER_Amount); 1241 *((void **) dst) = amounts; 1242 1243 for (uint32_t i = 0; i < header.dim; i++) 1244 { 1245 struct TALER_PQ_AmountP ap; 1246 struct TALER_Amount *amount = &amounts[i]; 1247 uint32_t val; 1248 size_t sz; 1249 1250 GNUNET_memcpy (&val, 1251 in, 1252 sizeof(val)); 1253 sz = ntohl (val); 1254 in += sizeof(val); 1255 1256 /* total size for this array-entry */ 1257 FAIL_IF (sizeof(ap) != sz); 1258 1259 GNUNET_memcpy (&ap, 1260 in, 1261 sz); 1262 FAIL_IF (2 != ntohl (ap.cnt)); 1263 1264 amount->value = GNUNET_ntohll (ap.v); 1265 amount->fraction = ntohl (ap.f); 1266 GNUNET_memcpy (amount->currency, 1267 info->currency, 1268 TALER_CURRENCY_LEN); 1269 1270 in += sizeof(struct TALER_PQ_AmountP); 1271 } 1272 return GNUNET_OK; 1273 } 1274 case TALER_PQ_array_of_amount_currency: 1275 { 1276 struct TALER_Amount *amounts; 1277 if (NULL != dst_size) 1278 *dst_size = sizeof(struct TALER_Amount) * (header.dim); 1279 1280 amounts = GNUNET_new_array (header.dim, 1281 struct TALER_Amount); 1282 *((void **) dst) = amounts; 1283 1284 for (uint32_t i = 0; i < header.dim; i++) 1285 { 1286 struct TALER_PQ_AmountCurrencyP ap; 1287 struct TALER_Amount *amount = &amounts[i]; 1288 uint32_t val; 1289 size_t sz; 1290 1291 GNUNET_memcpy (&val, 1292 in, 1293 sizeof(val)); 1294 sz = ntohl (val); 1295 in += sizeof(val); 1296 1297 FAIL_IF ( (sz >= sizeof(ap)) || 1298 (sz <= sizeof(ap) - TALER_CURRENCY_LEN) ); 1299 1300 memset (&ap, 1301 0, 1302 sizeof(ap)); 1303 GNUNET_memcpy (&ap, 1304 in, 1305 sz); 1306 FAIL_IF (3 != ntohl (ap.cnt)); 1307 1308 amount->value = GNUNET_ntohll (ap.v); 1309 amount->fraction = ntohl (ap.f); 1310 GNUNET_memcpy (amount->currency, 1311 ap.c, 1312 TALER_CURRENCY_LEN); 1313 1314 FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]); 1315 FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE); 1316 FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE); 1317 1318 in += sz; 1319 } 1320 return GNUNET_OK; 1321 } 1322 case TALER_PQ_array_of_denom_hash: 1323 if (NULL != dst_size) 1324 *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim); 1325 out = GNUNET_new_array (header.dim, 1326 struct TALER_DenominationHashP); 1327 *((void **) dst) = out; 1328 for (uint32_t i = 0; i < header.dim; i++) 1329 { 1330 uint32_t val; 1331 size_t sz; 1332 1333 GNUNET_memcpy (&val, 1334 in, 1335 sizeof(val)); 1336 sz = ntohl (val); 1337 FAIL_IF (sz != sizeof(struct TALER_DenominationHashP)); 1338 in += sizeof(uint32_t); 1339 *(struct TALER_DenominationHashP *) out = 1340 *(struct TALER_DenominationHashP *) in; 1341 in += sz; 1342 out += sz; 1343 } 1344 return GNUNET_OK; 1345 1346 case TALER_PQ_array_of_hash_code: 1347 if (NULL != dst_size) 1348 *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim); 1349 out = GNUNET_new_array (header.dim, 1350 struct GNUNET_HashCode); 1351 *((void **) dst) = out; 1352 for (uint32_t i = 0; i < header.dim; i++) 1353 { 1354 uint32_t val; 1355 size_t sz; 1356 1357 GNUNET_memcpy (&val, 1358 in, 1359 sizeof(val)); 1360 sz = ntohl (val); 1361 FAIL_IF (sz != sizeof(struct GNUNET_HashCode)); 1362 in += sizeof(uint32_t); 1363 *(struct GNUNET_HashCode *) out = 1364 *(struct GNUNET_HashCode *) in; 1365 in += sz; 1366 out += sz; 1367 } 1368 return GNUNET_OK; 1369 1370 case TALER_PQ_array_of_blinded_coin_hash: 1371 if (NULL != dst_size) 1372 *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim); 1373 out = GNUNET_new_array (header.dim, 1374 struct TALER_BlindedCoinHashP); 1375 *((void **) dst) = out; 1376 for (uint32_t i = 0; i < header.dim; i++) 1377 { 1378 uint32_t val; 1379 size_t sz; 1380 1381 GNUNET_memcpy (&val, 1382 in, 1383 sizeof(val)); 1384 sz = ntohl (val); 1385 FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP)); 1386 in += sizeof(uint32_t); 1387 *(struct TALER_BlindedCoinHashP *) out = 1388 *(struct TALER_BlindedCoinHashP *) in; 1389 in += sz; 1390 out += sz; 1391 } 1392 return GNUNET_OK; 1393 1394 case TALER_PQ_array_of_cs_r_pub: 1395 if (NULL != dst_size) 1396 *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim); 1397 out = GNUNET_new_array (header.dim, 1398 struct GNUNET_CRYPTO_CSPublicRPairP); 1399 *((void **) dst) = out; 1400 for (uint32_t i = 0; i < header.dim; i++) 1401 { 1402 uint32_t val; 1403 size_t sz; 1404 1405 GNUNET_memcpy (&val, 1406 in, 1407 sizeof(val)); 1408 sz = ntohl (val); 1409 FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP)); 1410 in += sizeof(uint32_t); 1411 *(struct GNUNET_CRYPTO_CSPublicRPairP *) out = 1412 *(struct GNUNET_CRYPTO_CSPublicRPairP *) in; 1413 in += sz; 1414 out += sz; 1415 } 1416 return GNUNET_OK; 1417 1418 case TALER_PQ_array_of_blinded_denom_sig: 1419 { 1420 struct TALER_BlindedDenominationSignature *denom_sigs; 1421 if (0 == header.dim) 1422 { 1423 if (NULL != dst_size) 1424 *dst_size = 0; 1425 break; 1426 } 1427 1428 denom_sigs = GNUNET_new_array (header.dim, 1429 struct TALER_BlindedDenominationSignature); 1430 *((void **) dst) = denom_sigs; 1431 1432 /* copy data */ 1433 for (uint32_t i = 0; i < header.dim; i++) 1434 { 1435 struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i]; 1436 struct GNUNET_CRYPTO_BlindedSignature *bs; 1437 uint32_t be[2]; 1438 uint32_t val; 1439 size_t sz; 1440 1441 GNUNET_memcpy (&val, 1442 in, 1443 sizeof(val)); 1444 sz = ntohl (val); 1445 FAIL_IF (sizeof(be) > sz); 1446 1447 in += sizeof(val); 1448 GNUNET_memcpy (&be, 1449 in, 1450 sizeof(be)); 1451 FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */ 1452 1453 in += sizeof(be); 1454 sz -= sizeof(be); 1455 bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 1456 bs->cipher = ntohl (be[0]); 1457 bs->rc = 1; 1458 switch (bs->cipher) 1459 { 1460 case GNUNET_CRYPTO_BSA_RSA: 1461 bs->details.blinded_rsa_signature 1462 = GNUNET_CRYPTO_rsa_signature_decode (in, 1463 sz); 1464 if (NULL == bs->details.blinded_rsa_signature) 1465 { 1466 GNUNET_free (bs); 1467 FAIL_IF (true); 1468 } 1469 break; 1470 case GNUNET_CRYPTO_BSA_CS: 1471 if (sizeof(bs->details.blinded_cs_answer) != sz) 1472 { 1473 GNUNET_free (bs); 1474 FAIL_IF (true); 1475 } 1476 GNUNET_memcpy (&bs->details.blinded_cs_answer, 1477 in, 1478 sz); 1479 break; 1480 default: 1481 GNUNET_free (bs); 1482 FAIL_IF (true); 1483 } 1484 denom_sig->blinded_sig = bs; 1485 in += sz; 1486 } 1487 return GNUNET_OK; 1488 } 1489 default: 1490 FAIL_IF (true); 1491 } 1492 } 1493 FAIL: 1494 GNUNET_free (*(void **) dst); 1495 return GNUNET_SYSERR; 1496 #undef FAIL_IF 1497 } 1498 1499 1500 /** 1501 * Cleanup of the data and closure of an array spec. 1502 */ 1503 static void 1504 array_cleanup (void *cls, 1505 void *rd) 1506 { 1507 struct ArrayResultCls *info = cls; 1508 void **dst = rd; 1509 1510 if ( (0 == info->same_size) && 1511 (NULL != info->sizes) ) 1512 GNUNET_free (*(info->sizes)); 1513 1514 /* Clean up signatures, if applicable */ 1515 if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) && 1516 (NULL != *dst)) 1517 { 1518 struct TALER_BlindedDenominationSignature *denom_sigs = *dst; 1519 1520 GNUNET_assert (NULL != info->num); 1521 for (size_t i = 0; i < *info->num; i++) 1522 GNUNET_free (denom_sigs[i].blinded_sig); 1523 } 1524 GNUNET_free (info); 1525 GNUNET_free (*dst); 1526 *dst = NULL; 1527 } 1528 1529 1530 struct GNUNET_PQ_ResultSpec 1531 TALER_PQ_result_spec_array_blinded_denom_sig ( 1532 struct GNUNET_PQ_Context *db, 1533 const char *name, 1534 size_t *num, 1535 struct TALER_BlindedDenominationSignature **denom_sigs) 1536 { 1537 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1538 1539 info->num = num; 1540 info->typ = TALER_PQ_array_of_blinded_denom_sig; 1541 GNUNET_assert (GNUNET_OK == 1542 GNUNET_PQ_get_oid_by_name (db, 1543 "bytea", 1544 &info->oid)); 1545 { 1546 struct GNUNET_PQ_ResultSpec res = { 1547 .conv = extract_array_generic, 1548 .cleaner = &array_cleanup, 1549 .dst = (void *) denom_sigs, 1550 .fname = name, 1551 .cls = info 1552 }; 1553 1554 return res; 1555 } 1556 } 1557 1558 1559 struct GNUNET_PQ_ResultSpec 1560 TALER_PQ_result_spec_array_blinded_coin_hash ( 1561 struct GNUNET_PQ_Context *db, 1562 const char *name, 1563 size_t *num, 1564 struct TALER_BlindedCoinHashP **h_coin_evs) 1565 { 1566 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1567 1568 info->num = num; 1569 info->typ = TALER_PQ_array_of_blinded_coin_hash; 1570 GNUNET_assert (GNUNET_OK == 1571 GNUNET_PQ_get_oid_by_name (db, 1572 "bytea", 1573 &info->oid)); 1574 { 1575 struct GNUNET_PQ_ResultSpec res = { 1576 .conv = extract_array_generic, 1577 .cleaner = &array_cleanup, 1578 .dst = (void *) h_coin_evs, 1579 .fname = name, 1580 .cls = info 1581 }; 1582 1583 return res; 1584 } 1585 } 1586 1587 1588 struct GNUNET_PQ_ResultSpec 1589 TALER_PQ_result_spec_array_denom_hash ( 1590 struct GNUNET_PQ_Context *db, 1591 const char *name, 1592 size_t *num, 1593 struct TALER_DenominationHashP **denom_hs) 1594 { 1595 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1596 1597 info->num = num; 1598 info->typ = TALER_PQ_array_of_denom_hash; 1599 GNUNET_assert (GNUNET_OK == 1600 GNUNET_PQ_get_oid_by_name (db, 1601 "bytea", 1602 &info->oid)); 1603 { 1604 struct GNUNET_PQ_ResultSpec res = { 1605 .conv = extract_array_generic, 1606 .cleaner = &array_cleanup, 1607 .dst = (void *) denom_hs, 1608 .fname = name, 1609 .cls = info 1610 }; 1611 1612 return res; 1613 } 1614 } 1615 1616 1617 struct GNUNET_PQ_ResultSpec 1618 TALER_PQ_result_spec_array_amount ( 1619 struct GNUNET_PQ_Context *db, 1620 const char *name, 1621 const char *currency, 1622 size_t *num, 1623 struct TALER_Amount **amounts) 1624 { 1625 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1626 1627 info->num = num; 1628 info->typ = TALER_PQ_array_of_amount; 1629 info->db = db; 1630 GNUNET_assert (GNUNET_OK == 1631 GNUNET_PQ_get_oid_by_name (db, 1632 "taler_amount", 1633 &info->oid)); 1634 1635 { 1636 size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1, 1637 strlen (currency)); 1638 GNUNET_memcpy (&info->currency, 1639 currency, 1640 clen); 1641 } 1642 { 1643 struct GNUNET_PQ_ResultSpec res = { 1644 .conv = extract_array_generic, 1645 .cleaner = &array_cleanup, 1646 .dst = (void *) amounts, 1647 .fname = name, 1648 .cls = info, 1649 }; 1650 1651 return res; 1652 } 1653 } 1654 1655 1656 struct GNUNET_PQ_ResultSpec 1657 TALER_PQ_result_spec_array_amount_with_currency ( 1658 struct GNUNET_PQ_Context *db, 1659 const char *name, 1660 size_t *num, 1661 struct TALER_Amount **amounts) 1662 { 1663 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1664 1665 info->num = num; 1666 info->typ = TALER_PQ_array_of_amount_currency; 1667 info->db = db; 1668 GNUNET_assert (GNUNET_OK == 1669 GNUNET_PQ_get_oid_by_name (db, 1670 "taler_amount_currency", 1671 &info->oid)); 1672 1673 { 1674 struct GNUNET_PQ_ResultSpec res = { 1675 .conv = extract_array_generic, 1676 .cleaner = &array_cleanup, 1677 .dst = (void *) amounts, 1678 .fname = name, 1679 .cls = info, 1680 }; 1681 1682 return res; 1683 } 1684 } 1685 1686 1687 struct GNUNET_PQ_ResultSpec 1688 TALER_PQ_result_spec_array_hash_code ( 1689 struct GNUNET_PQ_Context *db, 1690 const char *name, 1691 size_t *num, 1692 struct GNUNET_HashCode **hashes) 1693 { 1694 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1695 1696 info->num = num; 1697 info->typ = TALER_PQ_array_of_hash_code; 1698 info->db = db; 1699 GNUNET_assert (GNUNET_OK == 1700 GNUNET_PQ_get_oid_by_name (db, 1701 "gnunet_hashcode", 1702 &info->oid)); 1703 { 1704 struct GNUNET_PQ_ResultSpec res = { 1705 .conv = extract_array_generic, 1706 .cleaner = &array_cleanup, 1707 .dst = (void *) hashes, 1708 .fname = name, 1709 .cls = info, 1710 }; 1711 1712 return res; 1713 } 1714 } 1715 1716 1717 struct GNUNET_PQ_ResultSpec 1718 TALER_PQ_result_spec_array_cs_r_pub ( 1719 struct GNUNET_PQ_Context *db, 1720 const char *name, 1721 size_t *num, 1722 struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs) 1723 { 1724 struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); 1725 1726 info->num = num; 1727 info->typ = TALER_PQ_array_of_cs_r_pub; 1728 GNUNET_assert (GNUNET_OK == 1729 GNUNET_PQ_get_oid_by_name (db, 1730 "bytea", 1731 &info->oid)); 1732 { 1733 struct GNUNET_PQ_ResultSpec res = { 1734 .conv = extract_array_generic, 1735 .cleaner = &array_cleanup, 1736 .dst = (void *) cs_r_pubs, 1737 .fname = name, 1738 .cls = info 1739 }; 1740 1741 return res; 1742 } 1743 } 1744 1745 1746 /* end of pq_result_helper.c */