pq_query_helper.c (35418B)
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_query_helper.c 18 * @brief functions to initialize parameter arrays 19 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 20 * @author Florian Dold 21 * @author Christian Grothoff 22 */ 23 #include <gnunet/gnunet_common.h> 24 #include <gnunet/gnunet_util_lib.h> 25 #include <gnunet/gnunet_pq_lib.h> 26 #include "taler/taler_pq_lib.h" 27 #include "pq_common.h" 28 29 30 /** 31 * Function called to convert input amount into SQL parameter as tuple. 32 * 33 * @param cls closure 34 * @param data pointer to input argument, here a `struct TALER_Amount` 35 * @param data_len number of bytes in @a data (if applicable) 36 * @param[out] param_values SQL data to set 37 * @param[out] param_lengths SQL length data to set 38 * @param[out] param_formats SQL format data to set 39 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 40 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 41 * @param scratch_length number of entries left in @a scratch 42 * @return -1 on error, number of offsets used in @a scratch otherwise 43 */ 44 static int 45 qconv_amount_currency_tuple (void *cls, 46 const void *data, 47 size_t data_len, 48 void *param_values[], 49 int param_lengths[], 50 int param_formats[], 51 unsigned int param_length, 52 void *scratch[], 53 unsigned int scratch_length) 54 { 55 struct GNUNET_PQ_Context *db = cls; 56 const struct TALER_Amount *amount = data; 57 size_t sz; 58 59 GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid)); 60 GNUNET_assert (NULL != db); 61 GNUNET_assert (NULL != amount); 62 GNUNET_assert (1 == param_length); 63 GNUNET_assert (1 <= scratch_length); 64 GNUNET_assert (sizeof (struct TALER_Amount) == data_len); 65 { 66 char *out; 67 Oid oid_v; 68 Oid oid_f; 69 Oid oid_c; 70 struct TALER_PQ_AmountCurrencyP d; 71 72 GNUNET_assert (GNUNET_OK == 73 GNUNET_PQ_get_oid_by_name (db, 74 "int8", 75 &oid_v)); 76 GNUNET_assert (GNUNET_OK == 77 GNUNET_PQ_get_oid_by_name (db, 78 "int4", 79 &oid_f)); 80 GNUNET_assert (GNUNET_OK == 81 GNUNET_PQ_get_oid_by_name (db, 82 "varchar", 83 &oid_c)); 84 sz = TALER_PQ_make_taler_pq_amount_currency_ (amount, 85 oid_v, 86 oid_f, 87 oid_c, 88 &d); 89 out = GNUNET_malloc (sz); 90 memcpy (out, 91 &d, 92 sz); 93 scratch[0] = out; 94 } 95 96 param_values[0] = scratch[0]; 97 param_lengths[0] = sz; 98 param_formats[0] = 1; 99 100 return 1; 101 } 102 103 104 struct GNUNET_PQ_QueryParam 105 TALER_PQ_query_param_amount_with_currency ( 106 const struct GNUNET_PQ_Context *db, 107 const struct TALER_Amount *amount) 108 { 109 struct GNUNET_PQ_QueryParam res = { 110 .conv_cls = (void *) db, 111 .conv = &qconv_amount_currency_tuple, 112 .data = amount, 113 .size = sizeof (*amount), 114 .num_params = 1, 115 }; 116 117 return res; 118 } 119 120 121 /** 122 * Function called to convert input amount into SQL parameter as tuple. 123 * 124 * @param cls closure 125 * @param data pointer to input argument, here a `struct TALER_Amount` 126 * @param data_len number of bytes in @a data (if applicable) 127 * @param[out] param_values SQL data to set 128 * @param[out] param_lengths SQL length data to set 129 * @param[out] param_formats SQL format data to set 130 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 131 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 132 * @param scratch_length number of entries left in @a scratch 133 * @return -1 on error, number of offsets used in @a scratch otherwise 134 */ 135 static int 136 qconv_amount_tuple (void *cls, 137 const void *data, 138 size_t data_len, 139 void *param_values[], 140 int param_lengths[], 141 int param_formats[], 142 unsigned int param_length, 143 void *scratch[], 144 unsigned int scratch_length) 145 { 146 struct GNUNET_PQ_Context *db = cls; 147 const struct TALER_Amount *amount = data; 148 size_t sz; 149 150 GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid)); 151 GNUNET_assert (NULL != db); 152 GNUNET_assert (NULL != amount); 153 GNUNET_assert (1 == param_length); 154 GNUNET_assert (1 <= scratch_length); 155 GNUNET_assert (sizeof (struct TALER_Amount) == data_len); 156 { 157 char *out; 158 Oid oid_v; 159 Oid oid_f; 160 161 GNUNET_assert (GNUNET_OK == 162 GNUNET_PQ_get_oid_by_name (db, 163 "int8", 164 &oid_v)); 165 GNUNET_assert (GNUNET_OK == 166 GNUNET_PQ_get_oid_by_name (db, 167 "int4", 168 &oid_f)); 169 170 { 171 struct TALER_PQ_AmountP d 172 = TALER_PQ_make_taler_pq_amount_ (amount, 173 oid_v, 174 oid_f); 175 176 sz = sizeof(d); 177 out = GNUNET_malloc (sz); 178 scratch[0] = out; 179 GNUNET_memcpy (out, 180 &d, 181 sizeof(d)); 182 } 183 } 184 185 param_values[0] = scratch[0]; 186 param_lengths[0] = sz; 187 param_formats[0] = 1; 188 189 return 1; 190 } 191 192 193 struct GNUNET_PQ_QueryParam 194 TALER_PQ_query_param_amount ( 195 const struct GNUNET_PQ_Context *db, 196 const struct TALER_Amount *amount) 197 { 198 struct GNUNET_PQ_QueryParam res = { 199 .conv_cls = (void *) db, 200 .conv = &qconv_amount_tuple, 201 .data = amount, 202 .size = sizeof (*amount), 203 .num_params = 1, 204 }; 205 206 return res; 207 } 208 209 210 /** 211 * Function called to convert input argument into SQL parameters. 212 * 213 * @param cls closure 214 * @param data pointer to input argument 215 * @param data_len number of bytes in @a data (if applicable) 216 * @param[out] param_values SQL data to set 217 * @param[out] param_lengths SQL length data to set 218 * @param[out] param_formats SQL format data to set 219 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 220 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 221 * @param scratch_length number of entries left in @a scratch 222 * @return -1 on error, number of offsets used in @a scratch otherwise 223 */ 224 static int 225 qconv_denom_pub (void *cls, 226 const void *data, 227 size_t data_len, 228 void *param_values[], 229 int param_lengths[], 230 int param_formats[], 231 unsigned int param_length, 232 void *scratch[], 233 unsigned int scratch_length) 234 { 235 const struct TALER_DenominationPublicKey *denom_pub = data; 236 const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp = denom_pub->bsign_pub_key; 237 size_t tlen; 238 size_t len; 239 uint32_t be[2]; 240 char *buf; 241 void *tbuf; 242 243 (void) cls; 244 (void) data_len; 245 GNUNET_assert (1 == param_length); 246 GNUNET_assert (scratch_length > 0); 247 GNUNET_break (NULL == cls); 248 be[0] = htonl ((uint32_t) bsp->cipher); 249 be[1] = htonl (denom_pub->age_mask.bits); 250 switch (bsp->cipher) 251 { 252 case GNUNET_CRYPTO_BSA_RSA: 253 tlen = GNUNET_CRYPTO_rsa_public_key_encode ( 254 bsp->details.rsa_public_key, 255 &tbuf); 256 break; 257 case GNUNET_CRYPTO_BSA_CS: 258 tlen = sizeof (bsp->details.cs_public_key); 259 break; 260 default: 261 GNUNET_assert (0); 262 } 263 len = tlen + sizeof (be); 264 buf = GNUNET_malloc (len); 265 GNUNET_memcpy (buf, 266 be, 267 sizeof (be)); 268 switch (bsp->cipher) 269 { 270 case GNUNET_CRYPTO_BSA_RSA: 271 GNUNET_memcpy (&buf[sizeof (be)], 272 tbuf, 273 tlen); 274 GNUNET_free (tbuf); 275 break; 276 case GNUNET_CRYPTO_BSA_CS: 277 GNUNET_memcpy (&buf[sizeof (be)], 278 &bsp->details.cs_public_key, 279 tlen); 280 break; 281 default: 282 GNUNET_assert (0); 283 } 284 285 scratch[0] = buf; 286 param_values[0] = (void *) buf; 287 param_lengths[0] = len; 288 param_formats[0] = 1; 289 return 1; 290 } 291 292 293 struct GNUNET_PQ_QueryParam 294 TALER_PQ_query_param_denom_pub ( 295 const struct TALER_DenominationPublicKey *denom_pub) 296 { 297 struct GNUNET_PQ_QueryParam res = { 298 .conv = &qconv_denom_pub, 299 .data = denom_pub, 300 .num_params = 1 301 }; 302 303 return res; 304 } 305 306 307 struct GNUNET_PQ_QueryParam 308 TALER_PQ_query_param_denom_sig ( 309 const struct TALER_DenominationSignature *denom_sig) 310 { 311 return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig); 312 } 313 314 315 struct GNUNET_PQ_QueryParam 316 TALER_PQ_query_param_blinded_denom_sig ( 317 const struct TALER_BlindedDenominationSignature *denom_sig) 318 { 319 return GNUNET_PQ_query_param_blinded_sig (denom_sig->blinded_sig); 320 } 321 322 323 /** 324 * Function called to convert input argument into SQL parameters. 325 * 326 * @param cls closure 327 * @param data pointer to input argument 328 * @param data_len number of bytes in @a data (if applicable) 329 * @param[out] param_values SQL data to set 330 * @param[out] param_lengths SQL length data to set 331 * @param[out] param_formats SQL format data to set 332 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 333 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 334 * @param scratch_length number of entries left in @a scratch 335 * @return -1 on error, number of offsets used in @a scratch otherwise 336 */ 337 static int 338 qconv_blinded_planchet (void *cls, 339 const void *data, 340 size_t data_len, 341 void *param_values[], 342 int param_lengths[], 343 int param_formats[], 344 unsigned int param_length, 345 void *scratch[], 346 unsigned int scratch_length) 347 { 348 const struct TALER_BlindedPlanchet *bp = data; 349 const struct GNUNET_CRYPTO_BlindedMessage *bm = bp->blinded_message; 350 size_t tlen; 351 size_t len; 352 uint32_t be[2]; 353 char *buf; 354 355 (void) cls; 356 (void) data_len; 357 GNUNET_assert (1 == param_length); 358 GNUNET_assert (scratch_length > 0); 359 GNUNET_break (NULL == cls); 360 be[0] = htonl ((uint32_t) bm->cipher); 361 be[1] = htonl (0x0100); /* magic marker: blinded */ 362 switch (bm->cipher) 363 { 364 case GNUNET_CRYPTO_BSA_RSA: 365 tlen = bm->details.rsa_blinded_message.blinded_msg_size; 366 break; 367 case GNUNET_CRYPTO_BSA_CS: 368 tlen = sizeof (bm->details.cs_blinded_message); 369 break; 370 default: 371 GNUNET_assert (0); 372 } 373 len = tlen + sizeof (be); 374 buf = GNUNET_malloc (len); 375 GNUNET_memcpy (buf, 376 &be, 377 sizeof (be)); 378 switch (bm->cipher) 379 { 380 case GNUNET_CRYPTO_BSA_RSA: 381 GNUNET_memcpy (&buf[sizeof (be)], 382 bm->details.rsa_blinded_message.blinded_msg, 383 tlen); 384 break; 385 case GNUNET_CRYPTO_BSA_CS: 386 GNUNET_memcpy (&buf[sizeof (be)], 387 &bm->details.cs_blinded_message, 388 tlen); 389 break; 390 default: 391 GNUNET_assert (0); 392 } 393 scratch[0] = buf; 394 param_values[0] = (void *) buf; 395 param_lengths[0] = len; 396 param_formats[0] = 1; 397 return 1; 398 } 399 400 401 struct GNUNET_PQ_QueryParam 402 TALER_PQ_query_param_blinded_planchet ( 403 const struct TALER_BlindedPlanchet *bp) 404 { 405 struct GNUNET_PQ_QueryParam res = { 406 .conv = &qconv_blinded_planchet, 407 .data = bp, 408 .num_params = 1 409 }; 410 411 return res; 412 } 413 414 415 /** 416 * Function called to convert input argument into SQL parameters. 417 * 418 * @param cls closure 419 * @param data pointer to input argument 420 * @param data_len number of bytes in @a data (if applicable) 421 * @param[out] param_values SQL data to set 422 * @param[out] param_lengths SQL length data to set 423 * @param[out] param_formats SQL format data to set 424 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 425 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 426 * @param scratch_length number of entries left in @a scratch 427 * @return -1 on error, number of offsets used in @a scratch otherwise 428 */ 429 static int 430 qconv_exchange_blinding_values (void *cls, 431 const void *data, 432 size_t data_len, 433 void *param_values[], 434 int param_lengths[], 435 int param_formats[], 436 unsigned int param_length, 437 void *scratch[], 438 unsigned int scratch_length) 439 { 440 const struct TALER_ExchangeBlindingValues *blinding_values = data; 441 const struct GNUNET_CRYPTO_BlindingInputValues *bi = 442 blinding_values->blinding_inputs; 443 size_t tlen; 444 size_t len; 445 uint32_t be[2]; 446 char *buf; 447 448 (void) cls; 449 (void) data_len; 450 GNUNET_assert (1 == param_length); 451 GNUNET_assert (scratch_length > 0); 452 GNUNET_break (NULL == cls); 453 be[0] = htonl ((uint32_t) bi->cipher); 454 be[1] = htonl (0x010000); /* magic marker: EWV */ 455 switch (bi->cipher) 456 { 457 case GNUNET_CRYPTO_BSA_RSA: 458 tlen = 0; 459 break; 460 case GNUNET_CRYPTO_BSA_CS: 461 tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP); 462 break; 463 default: 464 GNUNET_assert (0); 465 } 466 len = tlen + sizeof (be); 467 buf = GNUNET_malloc (len); 468 GNUNET_memcpy (buf, 469 &be, 470 sizeof (be)); 471 switch (bi->cipher) 472 { 473 case GNUNET_CRYPTO_BSA_RSA: 474 break; 475 case GNUNET_CRYPTO_BSA_CS: 476 GNUNET_memcpy (&buf[sizeof (be)], 477 &bi->details.cs_values, 478 tlen); 479 break; 480 default: 481 GNUNET_assert (0); 482 } 483 scratch[0] = buf; 484 param_values[0] = (void *) buf; 485 param_lengths[0] = len; 486 param_formats[0] = 1; 487 return 1; 488 } 489 490 491 struct GNUNET_PQ_QueryParam 492 TALER_PQ_query_param_exchange_blinding_values ( 493 const struct TALER_ExchangeBlindingValues *blinding_values) 494 { 495 struct GNUNET_PQ_QueryParam res = { 496 .conv = &qconv_exchange_blinding_values, 497 .data = blinding_values, 498 .num_params = 1 499 }; 500 501 return res; 502 } 503 504 505 /** 506 * Function called to convert input argument into SQL parameters. 507 * 508 * @param cls closure 509 * @param data pointer to input argument, here a `json_t *` 510 * @param data_len number of bytes in @a data (if applicable) 511 * @param[out] param_values SQL data to set 512 * @param[out] param_lengths SQL length data to set 513 * @param[out] param_formats SQL format data to set 514 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 515 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 516 * @param scratch_length number of entries left in @a scratch 517 * @return -1 on error, number of offsets used in @a scratch otherwise 518 */ 519 static int 520 qconv_json (void *cls, 521 const void *data, 522 size_t data_len, 523 void *param_values[], 524 int param_lengths[], 525 int param_formats[], 526 unsigned int param_length, 527 void *scratch[], 528 unsigned int scratch_length) 529 { 530 const json_t *json = data; 531 char *str; 532 533 (void) cls; 534 (void) data_len; 535 GNUNET_assert (1 == param_length); 536 GNUNET_assert (scratch_length > 0); 537 str = json_dumps (json, 538 JSON_COMPACT); 539 if (NULL == str) 540 { 541 GNUNET_break (0); 542 return -1; 543 } 544 scratch[0] = str; 545 param_values[0] = (void *) str; 546 param_lengths[0] = strlen (str); 547 param_formats[0] = 1; 548 return 1; 549 } 550 551 552 struct GNUNET_PQ_QueryParam 553 TALER_PQ_query_param_json (const json_t *x) 554 { 555 struct GNUNET_PQ_QueryParam res = { 556 .conv = &qconv_json, 557 .data = x, 558 .num_params = 1 559 }; 560 561 return res; 562 } 563 564 565 /** ------------------- Array support -----------------------------------**/ 566 567 /** 568 * Closure for the array type handlers. 569 * 570 * May contain sizes information for the data, given (and handled) by the 571 * caller. 572 */ 573 struct qconv_array_cls 574 { 575 /** 576 * If not null, contains the array of sizes (the size of the array is the 577 * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free 578 * this memory. 579 * 580 * If not null, this value has precedence over @a sizes, which MUST be NULL */ 581 const size_t *sizes; 582 583 /** 584 * If @a size and @a c_sizes are NULL, this field defines the same size 585 * for each element in the array. 586 */ 587 size_t same_size; 588 589 /** 590 * If true, the array parameter to the data pointer to the qconv_array is a 591 * continuous byte array of data, either with @a same_size each or sizes 592 * provided bytes by @a sizes; 593 */ 594 bool continuous; 595 596 /** 597 * Type of the array elements 598 */ 599 enum TALER_PQ_ArrayType typ; 600 601 /** 602 * Oid of the array elements 603 */ 604 Oid oid; 605 606 /** 607 * db context, needed for OID-lookup of basis-types 608 */ 609 struct GNUNET_PQ_Context *db; 610 }; 611 612 /** 613 * Callback to cleanup a qconv_array_cls to be used during 614 * GNUNET_PQ_cleanup_query_params_closures 615 */ 616 static void 617 qconv_array_cls_cleanup (void *cls) 618 { 619 GNUNET_free (cls); 620 } 621 622 623 /** 624 * Function called to convert input argument into SQL parameters for arrays 625 * 626 * Note: the format for the encoding of arrays for libpq is not very well 627 * documented. We peeked into various sources (postgresql and libpqtypes) for 628 * guidance. 629 * 630 * @param cls Closure of type struct qconv_array_cls* 631 * @param data Pointer to first element in the array 632 * @param data_len Number of _elements_ in array @a data (if applicable) 633 * @param[out] param_values SQL data to set 634 * @param[out] param_lengths SQL length data to set 635 * @param[out] param_formats SQL format data to set 636 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 637 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 638 * @param scratch_length number of entries left in @a scratch 639 * @return -1 on error, number of offsets used in @a scratch otherwise 640 */ 641 static int 642 qconv_array ( 643 void *cls, 644 const void *data, 645 size_t data_len, 646 void *param_values[], 647 int param_lengths[], 648 int param_formats[], 649 unsigned int param_length, 650 void *scratch[], 651 unsigned int scratch_length) 652 { 653 struct qconv_array_cls *meta = cls; 654 size_t num = data_len; 655 size_t total_size; 656 const size_t *sizes; 657 bool same_sized; 658 void *elements = NULL; 659 bool noerror = true; 660 /* needed to capture the encoded rsa signatures */ 661 void **buffers = NULL; 662 size_t *buffer_lengths = NULL; 663 664 (void) (param_length); 665 (void) (scratch_length); 666 667 GNUNET_assert (NULL != meta); 668 GNUNET_assert (num < INT_MAX); 669 670 sizes = meta->sizes; 671 same_sized = (0 != meta->same_size); 672 673 #define RETURN_UNLESS(cond) \ 674 do { \ 675 if (! (cond)) \ 676 { \ 677 GNUNET_break ((cond)); \ 678 noerror = false; \ 679 goto DONE; \ 680 } \ 681 } while (0) 682 683 /* Calculate sizes and check bounds */ 684 { 685 /* num * length-field */ 686 size_t x = sizeof(uint32_t); 687 size_t y = x * num; 688 RETURN_UNLESS ((0 == num) || (y / num == x)); 689 690 /* size of header */ 691 total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P); 692 total_size += y; 693 RETURN_UNLESS (total_size >= x); 694 695 /* sizes of elements */ 696 if (same_sized) 697 { 698 x = num * meta->same_size; 699 RETURN_UNLESS ((0 == num) || (x / num == meta->same_size)); 700 701 y = total_size; 702 total_size += x; 703 RETURN_UNLESS (total_size >= y); 704 } 705 else /* sizes are different per element */ 706 { 707 switch (meta->typ) 708 { 709 case TALER_PQ_array_of_amount_currency: 710 { 711 const struct TALER_Amount *amounts = data; 712 Oid oid_v; 713 Oid oid_f; 714 Oid oid_c; 715 716 buffer_lengths = GNUNET_new_array (num, size_t); 717 /* hoist out of loop? */ 718 GNUNET_assert (GNUNET_OK == 719 GNUNET_PQ_get_oid_by_name (meta->db, 720 "int8", 721 &oid_v)); 722 GNUNET_assert (GNUNET_OK == 723 GNUNET_PQ_get_oid_by_name (meta->db, 724 "int4", 725 &oid_f)); 726 GNUNET_assert (GNUNET_OK == 727 GNUNET_PQ_get_oid_by_name (meta->db, 728 "varchar", 729 &oid_c)); 730 for (size_t i = 0; i<num; i++) 731 { 732 struct TALER_PQ_AmountCurrencyP am; 733 size_t len; 734 735 len = TALER_PQ_make_taler_pq_amount_currency_ ( 736 &amounts[i], 737 oid_v, 738 oid_f, 739 oid_c, 740 &am); 741 buffer_lengths[i] = len; 742 y = total_size; 743 total_size += len; 744 RETURN_UNLESS (total_size >= y); 745 } 746 sizes = buffer_lengths; 747 break; 748 } 749 case TALER_PQ_array_of_blinded_denom_sig: 750 { 751 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 752 size_t len; 753 754 buffers = GNUNET_new_array (num, void *); 755 buffer_lengths = GNUNET_new_array (num, size_t); 756 757 for (size_t i = 0; i<num; i++) 758 { 759 const struct GNUNET_CRYPTO_BlindedSignature *bs = 760 denom_sigs[i].blinded_sig; 761 762 switch (bs->cipher) 763 { 764 case GNUNET_CRYPTO_BSA_RSA: 765 len = GNUNET_CRYPTO_rsa_signature_encode ( 766 bs->details.blinded_rsa_signature, 767 &buffers[i]); 768 RETURN_UNLESS (len != 0); 769 break; 770 case GNUNET_CRYPTO_BSA_CS: 771 len = sizeof (bs->details.blinded_cs_answer); 772 break; 773 default: 774 GNUNET_assert (0); 775 } 776 777 /* for the cipher and marker */ 778 len += 2 * sizeof(uint32_t); 779 buffer_lengths[i] = len; 780 781 y = total_size; 782 total_size += len; 783 RETURN_UNLESS (total_size >= y); 784 } 785 sizes = buffer_lengths; 786 break; 787 } 788 default: 789 GNUNET_assert (0); 790 } 791 } 792 793 RETURN_UNLESS (INT_MAX > total_size); 794 RETURN_UNLESS (0 != total_size); 795 796 elements = GNUNET_malloc (total_size); 797 } 798 799 /* Write data */ 800 { 801 char *out = elements; 802 struct GNUNET_PQ_ArrayHeader_P h = { 803 .ndim = htonl (1), /* We only support one-dimensional arrays */ 804 .has_null = htonl (0), /* We do not support NULL entries in arrays */ 805 .lbound = htonl (1), /* Default start index value */ 806 .dim = htonl (num), 807 .oid = htonl (meta->oid), 808 }; 809 810 /* Write header */ 811 GNUNET_memcpy (out, 812 &h, 813 sizeof(h)); 814 out += sizeof(h); 815 816 /* Write elements */ 817 for (size_t i = 0; i < num; i++) 818 { 819 size_t sz = same_sized ? meta->same_size : sizes[i]; 820 uint32_t bsz = htonl ((uint32_t) sz); 821 822 /* Note: @a out is not necessarily aligned, as elements 823 may have odd sizes; so we must not type-pun here. */ 824 GNUNET_memcpy (out, 825 &bsz, 826 sizeof (bsz)); 827 out += sizeof(uint32_t); 828 switch (meta->typ) 829 { 830 case TALER_PQ_array_of_amount: 831 { 832 const struct TALER_Amount *amounts = data; 833 Oid oid_v; 834 Oid oid_f; 835 836 /* hoist out of loop? */ 837 GNUNET_assert (GNUNET_OK == 838 GNUNET_PQ_get_oid_by_name (meta->db, 839 "int8", 840 &oid_v)); 841 GNUNET_assert (GNUNET_OK == 842 GNUNET_PQ_get_oid_by_name (meta->db, 843 "int4", 844 &oid_f)); 845 { 846 struct TALER_PQ_AmountP am 847 = TALER_PQ_make_taler_pq_amount_ ( 848 &amounts[i], 849 oid_v, 850 oid_f); 851 852 GNUNET_memcpy (out, 853 &am, 854 sizeof(am)); 855 } 856 break; 857 } 858 case TALER_PQ_array_of_amount_currency: 859 { 860 const struct TALER_Amount *amounts = data; 861 Oid oid_v; 862 Oid oid_f; 863 Oid oid_c; 864 865 /* hoist out of loop? */ 866 GNUNET_assert (GNUNET_OK == 867 GNUNET_PQ_get_oid_by_name (meta->db, 868 "int8", 869 &oid_v)); 870 GNUNET_assert (GNUNET_OK == 871 GNUNET_PQ_get_oid_by_name (meta->db, 872 "int4", 873 &oid_f)); 874 GNUNET_assert (GNUNET_OK == 875 GNUNET_PQ_get_oid_by_name (meta->db, 876 "varchar", 877 &oid_c)); 878 { 879 struct TALER_PQ_AmountCurrencyP am; 880 size_t len; 881 882 len = TALER_PQ_make_taler_pq_amount_currency_ ( 883 &amounts[i], 884 oid_v, 885 oid_f, 886 oid_c, 887 &am); 888 GNUNET_memcpy (out, 889 &am, 890 len); 891 } 892 break; 893 } 894 case TALER_PQ_array_of_blinded_denom_sig: 895 { 896 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 897 const struct GNUNET_CRYPTO_BlindedSignature *bs = 898 denom_sigs[i].blinded_sig; 899 uint32_t be[2]; 900 901 be[0] = htonl ((uint32_t) bs->cipher); 902 be[1] = htonl (0x01); /* magic margker: blinded */ 903 GNUNET_memcpy (out, 904 &be, 905 sizeof(be)); 906 out += sizeof(be); 907 sz -= sizeof(be); 908 909 switch (bs->cipher) 910 { 911 case GNUNET_CRYPTO_BSA_RSA: 912 /* For RSA, 'same_sized' must have been false */ 913 GNUNET_assert (NULL != buffers); 914 GNUNET_memcpy (out, 915 buffers[i], 916 sz); 917 break; 918 case GNUNET_CRYPTO_BSA_CS: 919 GNUNET_memcpy (out, 920 &bs->details.blinded_cs_answer, 921 sz); 922 break; 923 default: 924 GNUNET_assert (0); 925 } 926 break; 927 } 928 case TALER_PQ_array_of_blinded_coin_hash: 929 { 930 const struct TALER_BlindedCoinHashP *coin_hs = data; 931 932 GNUNET_memcpy (out, 933 &coin_hs[i], 934 sizeof(struct TALER_BlindedCoinHashP)); 935 936 break; 937 } 938 case TALER_PQ_array_of_denom_hash: 939 { 940 const struct TALER_DenominationHashP *denom_hs = data; 941 942 GNUNET_memcpy (out, 943 &denom_hs[i], 944 sizeof(struct TALER_DenominationHashP)); 945 break; 946 } 947 case TALER_PQ_array_of_hash_code: 948 { 949 const struct GNUNET_HashCode *hashes = data; 950 951 GNUNET_memcpy (out, 952 &hashes[i], 953 sizeof(struct GNUNET_HashCode)); 954 break; 955 } 956 case TALER_PQ_array_of_cs_r_pub: 957 { 958 const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data; 959 960 GNUNET_memcpy (out, 961 &cs_r_pubs[i], 962 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP)); 963 break; 964 } 965 default: 966 { 967 GNUNET_assert (0); 968 break; 969 } 970 } 971 out += sz; 972 } 973 } 974 param_values[0] = elements; 975 param_lengths[0] = total_size; 976 param_formats[0] = 1; 977 scratch[0] = elements; 978 979 DONE: 980 if (NULL != buffers) 981 { 982 for (size_t i = 0; i<num; i++) 983 GNUNET_free (buffers[i]); 984 GNUNET_free (buffers); 985 } 986 GNUNET_free (buffer_lengths); 987 if (noerror) 988 return 1; 989 return -1; 990 } 991 992 993 /** 994 * Function to generate a typ specific query parameter and corresponding closure 995 * 996 * @param num Number of elements in @a elements 997 * @param continuous If true, @a elements is an continuous array of data 998 * @param elements Array of @a num elements, either continuous or pointers 999 * @param sizes Array of @a num sizes, one per element, may be NULL 1000 * @param same_size If not 0, all elements in @a elements have this size 1001 * @param typ Supported internal type of each element in @a elements 1002 * @param oid Oid of the type to be used in Postgres 1003 * @param[in,out] db our database handle for looking up OIDs 1004 * @return Query parameter 1005 */ 1006 static struct GNUNET_PQ_QueryParam 1007 query_param_array_generic ( 1008 unsigned int num, 1009 bool continuous, 1010 const void *elements, 1011 const size_t *sizes, 1012 size_t same_size, 1013 enum TALER_PQ_ArrayType typ, 1014 Oid oid, 1015 struct GNUNET_PQ_Context *db) 1016 { 1017 struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls); 1018 1019 meta->typ = typ; 1020 meta->oid = oid; 1021 meta->sizes = sizes; 1022 meta->same_size = same_size; 1023 meta->continuous = continuous; 1024 meta->db = db; 1025 1026 { 1027 struct GNUNET_PQ_QueryParam res = { 1028 .conv = qconv_array, 1029 .conv_cls = meta, 1030 .conv_cls_cleanup = qconv_array_cls_cleanup, 1031 .data = elements, 1032 .size = num, 1033 .num_params = 1, 1034 }; 1035 1036 return res; 1037 } 1038 } 1039 1040 1041 struct GNUNET_PQ_QueryParam 1042 TALER_PQ_query_param_array_blinded_denom_sig ( 1043 size_t num, 1044 const struct TALER_BlindedDenominationSignature *denom_sigs, 1045 struct GNUNET_PQ_Context *db) 1046 { 1047 Oid oid; 1048 1049 GNUNET_assert (GNUNET_OK == 1050 GNUNET_PQ_get_oid_by_name (db, 1051 "bytea", 1052 &oid)); 1053 return query_param_array_generic (num, 1054 true, 1055 denom_sigs, 1056 NULL, 1057 0, 1058 TALER_PQ_array_of_blinded_denom_sig, 1059 oid, 1060 NULL); 1061 } 1062 1063 1064 struct GNUNET_PQ_QueryParam 1065 TALER_PQ_query_param_array_blinded_coin_hash ( 1066 size_t num, 1067 const struct TALER_BlindedCoinHashP *coin_hs, 1068 struct GNUNET_PQ_Context *db) 1069 { 1070 Oid oid; 1071 1072 GNUNET_assert (GNUNET_OK == 1073 GNUNET_PQ_get_oid_by_name (db, 1074 "bytea", 1075 &oid)); 1076 return query_param_array_generic (num, 1077 true, 1078 coin_hs, 1079 NULL, 1080 sizeof(struct TALER_BlindedCoinHashP), 1081 TALER_PQ_array_of_blinded_coin_hash, 1082 oid, 1083 NULL); 1084 } 1085 1086 1087 struct GNUNET_PQ_QueryParam 1088 TALER_PQ_query_param_array_denom_hash ( 1089 size_t num, 1090 const struct TALER_DenominationHashP *denom_hs, 1091 struct GNUNET_PQ_Context *db) 1092 { 1093 Oid oid; 1094 1095 GNUNET_assert (GNUNET_OK == 1096 GNUNET_PQ_get_oid_by_name (db, 1097 "bytea", 1098 &oid)); 1099 return query_param_array_generic (num, 1100 true, 1101 denom_hs, 1102 NULL, 1103 sizeof(struct TALER_DenominationHashP), 1104 TALER_PQ_array_of_denom_hash, 1105 oid, 1106 NULL); 1107 } 1108 1109 1110 struct GNUNET_PQ_QueryParam 1111 TALER_PQ_query_param_array_hash_code ( 1112 size_t num, 1113 const struct GNUNET_HashCode *hashes, 1114 struct GNUNET_PQ_Context *db) 1115 { 1116 Oid oid; 1117 GNUNET_assert (GNUNET_OK == 1118 GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid)); 1119 return query_param_array_generic (num, 1120 true, 1121 hashes, 1122 NULL, 1123 sizeof(struct GNUNET_HashCode), 1124 TALER_PQ_array_of_hash_code, 1125 oid, 1126 NULL); 1127 } 1128 1129 1130 struct GNUNET_PQ_QueryParam 1131 TALER_PQ_query_param_array_amount ( 1132 size_t num, 1133 const struct TALER_Amount *amounts, 1134 struct GNUNET_PQ_Context *db) 1135 { 1136 Oid oid; 1137 1138 GNUNET_assert (GNUNET_OK == 1139 GNUNET_PQ_get_oid_by_name (db, 1140 "taler_amount", 1141 &oid)); 1142 return query_param_array_generic ( 1143 num, 1144 true, 1145 amounts, 1146 NULL, 1147 sizeof(struct TALER_PQ_AmountP), 1148 TALER_PQ_array_of_amount, 1149 oid, 1150 db); 1151 } 1152 1153 1154 struct GNUNET_PQ_QueryParam 1155 TALER_PQ_query_param_array_amount_with_currency ( 1156 size_t num, 1157 const struct TALER_Amount *amounts, 1158 const char *schema, 1159 struct GNUNET_PQ_Context *db) 1160 { 1161 Oid oid; 1162 char *tn; 1163 1164 if (NULL != schema) 1165 GNUNET_asprintf (&tn, 1166 "%s.taler_amount_currency", 1167 schema); 1168 else 1169 GNUNET_asprintf (&tn, 1170 "taler_amount_currency"); 1171 GNUNET_assert (GNUNET_OK == 1172 GNUNET_PQ_get_oid_by_name (db, 1173 tn, 1174 &oid)); 1175 GNUNET_free (tn); 1176 return query_param_array_generic ( 1177 num, 1178 true, 1179 amounts, 1180 NULL, 1181 0, /* currency is technically variable length */ 1182 TALER_PQ_array_of_amount_currency, 1183 oid, 1184 db); 1185 } 1186 1187 1188 struct GNUNET_PQ_QueryParam 1189 TALER_PQ_query_param_array_cs_r_pub ( 1190 size_t num, 1191 const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs, 1192 struct GNUNET_PQ_Context *db) 1193 { 1194 Oid oid; 1195 1196 GNUNET_assert (GNUNET_OK == 1197 GNUNET_PQ_get_oid_by_name (db, 1198 "bytea", 1199 &oid)); 1200 return query_param_array_generic ( 1201 num, 1202 true, 1203 cs_r_pubs, 1204 NULL, 1205 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP), 1206 TALER_PQ_array_of_cs_r_pub, 1207 oid, 1208 db); 1209 } 1210 1211 1212 /* end of pq/pq_query_helper.c */