Line data Source code
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 1 : 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 1 : struct GNUNET_PQ_Context *db = cls;
56 1 : const struct TALER_Amount *amount = data;
57 : size_t sz;
58 :
59 : GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
60 1 : GNUNET_assert (NULL != db);
61 1 : GNUNET_assert (NULL != amount);
62 1 : GNUNET_assert (1 == param_length);
63 1 : GNUNET_assert (1 <= scratch_length);
64 1 : 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 1 : GNUNET_assert (GNUNET_OK ==
73 : GNUNET_PQ_get_oid_by_name (db,
74 : "int8",
75 : &oid_v));
76 1 : GNUNET_assert (GNUNET_OK ==
77 : GNUNET_PQ_get_oid_by_name (db,
78 : "int4",
79 : &oid_f));
80 1 : GNUNET_assert (GNUNET_OK ==
81 : GNUNET_PQ_get_oid_by_name (db,
82 : "varchar",
83 : &oid_c));
84 1 : sz = TALER_PQ_make_taler_pq_amount_currency_ (amount,
85 : oid_v,
86 : oid_f,
87 : oid_c,
88 : &d);
89 1 : out = GNUNET_malloc (sz);
90 1 : memcpy (out,
91 : &d,
92 : sz);
93 1 : scratch[0] = out;
94 : }
95 :
96 1 : param_values[0] = scratch[0];
97 1 : param_lengths[0] = sz;
98 1 : param_formats[0] = 1;
99 :
100 1 : return 1;
101 : }
102 :
103 :
104 : struct GNUNET_PQ_QueryParam
105 1 : TALER_PQ_query_param_amount_with_currency (
106 : const struct GNUNET_PQ_Context *db,
107 : const struct TALER_Amount *amount)
108 : {
109 1 : 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 1 : 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 3640 : 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 3640 : struct GNUNET_PQ_Context *db = cls;
147 3640 : const struct TALER_Amount *amount = data;
148 : size_t sz;
149 :
150 : GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
151 3640 : GNUNET_assert (NULL != db);
152 3640 : GNUNET_assert (NULL != amount);
153 3640 : GNUNET_assert (1 == param_length);
154 3640 : GNUNET_assert (1 <= scratch_length);
155 3640 : GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
156 : {
157 : char *out;
158 : Oid oid_v;
159 : Oid oid_f;
160 :
161 3640 : GNUNET_assert (GNUNET_OK ==
162 : GNUNET_PQ_get_oid_by_name (db,
163 : "int8",
164 : &oid_v));
165 3640 : 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 3640 : = TALER_PQ_make_taler_pq_amount_ (amount,
173 : oid_v,
174 : oid_f);
175 :
176 3640 : sz = sizeof(d);
177 3640 : out = GNUNET_malloc (sz);
178 3640 : scratch[0] = out;
179 3640 : GNUNET_memcpy (out,
180 : &d,
181 : sizeof(d));
182 : }
183 : }
184 :
185 3640 : param_values[0] = scratch[0];
186 3640 : param_lengths[0] = sz;
187 3640 : param_formats[0] = 1;
188 :
189 3640 : return 1;
190 : }
191 :
192 :
193 : struct GNUNET_PQ_QueryParam
194 3640 : TALER_PQ_query_param_amount (
195 : const struct GNUNET_PQ_Context *db,
196 : const struct TALER_Amount *amount)
197 : {
198 3640 : 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 3640 : 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 517 : 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 517 : const struct TALER_DenominationPublicKey *denom_pub = data;
236 517 : 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 517 : GNUNET_assert (1 == param_length);
246 517 : GNUNET_assert (scratch_length > 0);
247 517 : GNUNET_break (NULL == cls);
248 517 : be[0] = htonl ((uint32_t) bsp->cipher);
249 517 : be[1] = htonl (denom_pub->age_mask.bits);
250 517 : switch (bsp->cipher)
251 : {
252 282 : case GNUNET_CRYPTO_BSA_RSA:
253 282 : tlen = GNUNET_CRYPTO_rsa_public_key_encode (
254 282 : bsp->details.rsa_public_key,
255 : &tbuf);
256 282 : break;
257 235 : case GNUNET_CRYPTO_BSA_CS:
258 235 : tlen = sizeof (bsp->details.cs_public_key);
259 235 : break;
260 0 : default:
261 0 : GNUNET_assert (0);
262 : }
263 517 : len = tlen + sizeof (be);
264 517 : buf = GNUNET_malloc (len);
265 517 : GNUNET_memcpy (buf,
266 : be,
267 : sizeof (be));
268 517 : switch (bsp->cipher)
269 : {
270 282 : case GNUNET_CRYPTO_BSA_RSA:
271 282 : GNUNET_memcpy (&buf[sizeof (be)],
272 : tbuf,
273 : tlen);
274 282 : GNUNET_free (tbuf);
275 282 : break;
276 235 : case GNUNET_CRYPTO_BSA_CS:
277 235 : GNUNET_memcpy (&buf[sizeof (be)],
278 : &bsp->details.cs_public_key,
279 : tlen);
280 235 : break;
281 0 : default:
282 0 : GNUNET_assert (0);
283 : }
284 :
285 517 : scratch[0] = buf;
286 517 : param_values[0] = (void *) buf;
287 517 : param_lengths[0] = len;
288 517 : param_formats[0] = 1;
289 517 : return 1;
290 : }
291 :
292 :
293 : struct GNUNET_PQ_QueryParam
294 517 : TALER_PQ_query_param_denom_pub (
295 : const struct TALER_DenominationPublicKey *denom_pub)
296 : {
297 517 : struct GNUNET_PQ_QueryParam res = {
298 : .conv = &qconv_denom_pub,
299 : .data = denom_pub,
300 : .num_params = 1
301 : };
302 :
303 517 : return res;
304 : }
305 :
306 :
307 : struct GNUNET_PQ_QueryParam
308 214 : TALER_PQ_query_param_denom_sig (
309 : const struct TALER_DenominationSignature *denom_sig)
310 : {
311 214 : return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig);
312 : }
313 :
314 :
315 : struct GNUNET_PQ_QueryParam
316 0 : TALER_PQ_query_param_blinded_denom_sig (
317 : const struct TALER_BlindedDenominationSignature *denom_sig)
318 : {
319 0 : 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 0 : 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 0 : const struct TALER_BlindedPlanchet *bp = data;
349 0 : 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 0 : GNUNET_assert (1 == param_length);
358 0 : GNUNET_assert (scratch_length > 0);
359 0 : GNUNET_break (NULL == cls);
360 0 : be[0] = htonl ((uint32_t) bm->cipher);
361 0 : be[1] = htonl (0x0100); /* magic marker: blinded */
362 0 : switch (bm->cipher)
363 : {
364 0 : case GNUNET_CRYPTO_BSA_RSA:
365 0 : tlen = bm->details.rsa_blinded_message.blinded_msg_size;
366 0 : break;
367 0 : case GNUNET_CRYPTO_BSA_CS:
368 0 : tlen = sizeof (bm->details.cs_blinded_message);
369 0 : break;
370 0 : default:
371 0 : GNUNET_assert (0);
372 : }
373 0 : len = tlen + sizeof (be);
374 0 : buf = GNUNET_malloc (len);
375 0 : GNUNET_memcpy (buf,
376 : &be,
377 : sizeof (be));
378 0 : switch (bm->cipher)
379 : {
380 0 : case GNUNET_CRYPTO_BSA_RSA:
381 0 : GNUNET_memcpy (&buf[sizeof (be)],
382 : bm->details.rsa_blinded_message.blinded_msg,
383 : tlen);
384 0 : break;
385 0 : case GNUNET_CRYPTO_BSA_CS:
386 0 : GNUNET_memcpy (&buf[sizeof (be)],
387 : &bm->details.cs_blinded_message,
388 : tlen);
389 0 : break;
390 0 : default:
391 0 : GNUNET_assert (0);
392 : }
393 0 : scratch[0] = buf;
394 0 : param_values[0] = (void *) buf;
395 0 : param_lengths[0] = len;
396 0 : param_formats[0] = 1;
397 0 : return 1;
398 : }
399 :
400 :
401 : struct GNUNET_PQ_QueryParam
402 0 : TALER_PQ_query_param_blinded_planchet (
403 : const struct TALER_BlindedPlanchet *bp)
404 : {
405 0 : struct GNUNET_PQ_QueryParam res = {
406 : .conv = &qconv_blinded_planchet,
407 : .data = bp,
408 : .num_params = 1
409 : };
410 :
411 0 : 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 0 : 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 0 : const struct TALER_ExchangeBlindingValues *blinding_values = data;
441 0 : 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 0 : GNUNET_assert (1 == param_length);
451 0 : GNUNET_assert (scratch_length > 0);
452 0 : GNUNET_break (NULL == cls);
453 0 : be[0] = htonl ((uint32_t) bi->cipher);
454 0 : be[1] = htonl (0x010000); /* magic marker: EWV */
455 0 : switch (bi->cipher)
456 : {
457 0 : case GNUNET_CRYPTO_BSA_RSA:
458 0 : tlen = 0;
459 0 : break;
460 0 : case GNUNET_CRYPTO_BSA_CS:
461 0 : tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP);
462 0 : break;
463 0 : default:
464 0 : GNUNET_assert (0);
465 : }
466 0 : len = tlen + sizeof (be);
467 0 : buf = GNUNET_malloc (len);
468 0 : GNUNET_memcpy (buf,
469 : &be,
470 : sizeof (be));
471 0 : switch (bi->cipher)
472 : {
473 0 : case GNUNET_CRYPTO_BSA_RSA:
474 0 : break;
475 0 : case GNUNET_CRYPTO_BSA_CS:
476 0 : GNUNET_memcpy (&buf[sizeof (be)],
477 : &bi->details.cs_values,
478 : tlen);
479 0 : break;
480 0 : default:
481 0 : GNUNET_assert (0);
482 : }
483 0 : scratch[0] = buf;
484 0 : param_values[0] = (void *) buf;
485 0 : param_lengths[0] = len;
486 0 : param_formats[0] = 1;
487 0 : return 1;
488 : }
489 :
490 :
491 : struct GNUNET_PQ_QueryParam
492 0 : TALER_PQ_query_param_exchange_blinding_values (
493 : const struct TALER_ExchangeBlindingValues *blinding_values)
494 : {
495 0 : struct GNUNET_PQ_QueryParam res = {
496 : .conv = &qconv_exchange_blinding_values,
497 : .data = blinding_values,
498 : .num_params = 1
499 : };
500 :
501 0 : 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 107 : 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 107 : const json_t *json = data;
531 : char *str;
532 :
533 : (void) cls;
534 : (void) data_len;
535 107 : GNUNET_assert (1 == param_length);
536 107 : GNUNET_assert (scratch_length > 0);
537 107 : str = json_dumps (json,
538 : JSON_COMPACT);
539 107 : if (NULL == str)
540 : {
541 0 : GNUNET_break (0);
542 0 : return -1;
543 : }
544 107 : scratch[0] = str;
545 107 : param_values[0] = (void *) str;
546 107 : param_lengths[0] = strlen (str);
547 107 : param_formats[0] = 1;
548 107 : return 1;
549 : }
550 :
551 :
552 : struct GNUNET_PQ_QueryParam
553 107 : TALER_PQ_query_param_json (const json_t *x)
554 : {
555 107 : struct GNUNET_PQ_QueryParam res = {
556 : .conv = &qconv_json,
557 : .data = x,
558 : .num_params = 1
559 : };
560 :
561 107 : 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 820 : qconv_array_cls_cleanup (void *cls)
618 : {
619 820 : GNUNET_free (cls);
620 820 : }
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 824 : 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 824 : struct qconv_array_cls *meta = cls;
654 824 : size_t num = data_len;
655 : size_t total_size;
656 : const size_t *sizes;
657 : bool same_sized;
658 824 : void *elements = NULL;
659 824 : bool noerror = true;
660 : /* needed to capture the encoded rsa signatures */
661 824 : void **buffers = NULL;
662 824 : size_t *buffer_lengths = NULL;
663 :
664 : (void) (param_length);
665 : (void) (scratch_length);
666 :
667 824 : GNUNET_assert (NULL != meta);
668 824 : GNUNET_assert (num < INT_MAX);
669 :
670 824 : sizes = meta->sizes;
671 824 : 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 824 : size_t x = sizeof(uint32_t);
687 824 : size_t y = x * num;
688 824 : RETURN_UNLESS ((0 == num) || (y / num == x));
689 :
690 : /* size of header */
691 824 : total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
692 824 : total_size += y;
693 824 : RETURN_UNLESS (total_size >= x);
694 :
695 : /* sizes of elements */
696 824 : if (same_sized)
697 : {
698 701 : x = num * meta->same_size;
699 701 : RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
700 :
701 701 : y = total_size;
702 701 : total_size += x;
703 701 : RETURN_UNLESS (total_size >= y);
704 : }
705 : else /* sizes are different per element */
706 : {
707 123 : switch (meta->typ)
708 : {
709 1 : case TALER_PQ_array_of_amount_currency:
710 : {
711 1 : const struct TALER_Amount *amounts = data;
712 : Oid oid_v;
713 : Oid oid_f;
714 : Oid oid_c;
715 :
716 1 : buffer_lengths = GNUNET_new_array (num, size_t);
717 : /* hoist out of loop? */
718 1 : GNUNET_assert (GNUNET_OK ==
719 : GNUNET_PQ_get_oid_by_name (meta->db,
720 : "int8",
721 : &oid_v));
722 1 : GNUNET_assert (GNUNET_OK ==
723 : GNUNET_PQ_get_oid_by_name (meta->db,
724 : "int4",
725 : &oid_f));
726 1 : GNUNET_assert (GNUNET_OK ==
727 : GNUNET_PQ_get_oid_by_name (meta->db,
728 : "varchar",
729 : &oid_c));
730 3 : for (size_t i = 0; i<num; i++)
731 : {
732 : struct TALER_PQ_AmountCurrencyP am;
733 : size_t len;
734 :
735 2 : len = TALER_PQ_make_taler_pq_amount_currency_ (
736 2 : &amounts[i],
737 : oid_v,
738 : oid_f,
739 : oid_c,
740 : &am);
741 2 : buffer_lengths[i] = len;
742 2 : y = total_size;
743 2 : total_size += len;
744 2 : RETURN_UNLESS (total_size >= y);
745 : }
746 1 : sizes = buffer_lengths;
747 1 : break;
748 : }
749 122 : case TALER_PQ_array_of_blinded_denom_sig:
750 : {
751 122 : const struct TALER_BlindedDenominationSignature *denom_sigs = data;
752 : size_t len;
753 :
754 122 : buffers = GNUNET_new_array (num, void *);
755 122 : buffer_lengths = GNUNET_new_array (num, size_t);
756 :
757 339 : for (size_t i = 0; i<num; i++)
758 : {
759 217 : const struct GNUNET_CRYPTO_BlindedSignature *bs =
760 217 : denom_sigs[i].blinded_sig;
761 :
762 217 : switch (bs->cipher)
763 : {
764 96 : case GNUNET_CRYPTO_BSA_RSA:
765 96 : len = GNUNET_CRYPTO_rsa_signature_encode (
766 96 : bs->details.blinded_rsa_signature,
767 96 : &buffers[i]);
768 96 : RETURN_UNLESS (len != 0);
769 96 : break;
770 121 : case GNUNET_CRYPTO_BSA_CS:
771 121 : len = sizeof (bs->details.blinded_cs_answer);
772 121 : break;
773 0 : default:
774 0 : GNUNET_assert (0);
775 : }
776 :
777 : /* for the cipher and marker */
778 217 : len += 2 * sizeof(uint32_t);
779 217 : buffer_lengths[i] = len;
780 :
781 217 : y = total_size;
782 217 : total_size += len;
783 217 : RETURN_UNLESS (total_size >= y);
784 : }
785 122 : sizes = buffer_lengths;
786 122 : break;
787 : }
788 0 : default:
789 0 : GNUNET_assert (0);
790 : }
791 : }
792 :
793 824 : RETURN_UNLESS (INT_MAX > total_size);
794 824 : RETURN_UNLESS (0 != total_size);
795 :
796 824 : elements = GNUNET_malloc (total_size);
797 : }
798 :
799 : /* Write data */
800 : {
801 824 : char *out = elements;
802 824 : struct GNUNET_PQ_ArrayHeader_P h = {
803 824 : .ndim = htonl (1), /* We only support one-dimensional arrays */
804 824 : .has_null = htonl (0), /* We do not support NULL entries in arrays */
805 824 : .lbound = htonl (1), /* Default start index value */
806 824 : .dim = htonl (num),
807 824 : .oid = htonl (meta->oid),
808 : };
809 :
810 : /* Write header */
811 824 : GNUNET_memcpy (out,
812 : &h,
813 : sizeof(h));
814 824 : out += sizeof(h);
815 :
816 : /* Write elements */
817 1727 : for (size_t i = 0; i < num; i++)
818 : {
819 903 : size_t sz = same_sized ? meta->same_size : sizes[i];
820 903 : 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 903 : GNUNET_memcpy (out,
825 : &bsz,
826 : sizeof (bsz));
827 903 : out += sizeof(uint32_t);
828 903 : switch (meta->typ)
829 : {
830 577 : case TALER_PQ_array_of_amount:
831 : {
832 577 : const struct TALER_Amount *amounts = data;
833 : Oid oid_v;
834 : Oid oid_f;
835 :
836 : /* hoist out of loop? */
837 577 : GNUNET_assert (GNUNET_OK ==
838 : GNUNET_PQ_get_oid_by_name (meta->db,
839 : "int8",
840 : &oid_v));
841 577 : 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 577 : = TALER_PQ_make_taler_pq_amount_ (
848 577 : &amounts[i],
849 : oid_v,
850 : oid_f);
851 :
852 577 : GNUNET_memcpy (out,
853 : &am,
854 : sizeof(am));
855 : }
856 577 : break;
857 : }
858 2 : case TALER_PQ_array_of_amount_currency:
859 : {
860 2 : 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 2 : GNUNET_assert (GNUNET_OK ==
867 : GNUNET_PQ_get_oid_by_name (meta->db,
868 : "int8",
869 : &oid_v));
870 2 : GNUNET_assert (GNUNET_OK ==
871 : GNUNET_PQ_get_oid_by_name (meta->db,
872 : "int4",
873 : &oid_f));
874 2 : 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 2 : len = TALER_PQ_make_taler_pq_amount_currency_ (
883 2 : &amounts[i],
884 : oid_v,
885 : oid_f,
886 : oid_c,
887 : &am);
888 2 : GNUNET_memcpy (out,
889 : &am,
890 : len);
891 : }
892 2 : break;
893 : }
894 217 : case TALER_PQ_array_of_blinded_denom_sig:
895 : {
896 217 : const struct TALER_BlindedDenominationSignature *denom_sigs = data;
897 217 : const struct GNUNET_CRYPTO_BlindedSignature *bs =
898 217 : denom_sigs[i].blinded_sig;
899 : uint32_t be[2];
900 :
901 217 : be[0] = htonl ((uint32_t) bs->cipher);
902 217 : be[1] = htonl (0x01); /* magic margker: blinded */
903 217 : GNUNET_memcpy (out,
904 : &be,
905 : sizeof(be));
906 217 : out += sizeof(be);
907 217 : sz -= sizeof(be);
908 :
909 217 : switch (bs->cipher)
910 : {
911 96 : case GNUNET_CRYPTO_BSA_RSA:
912 : /* For RSA, 'same_sized' must have been false */
913 96 : GNUNET_assert (NULL != buffers);
914 96 : GNUNET_memcpy (out,
915 : buffers[i],
916 : sz);
917 96 : break;
918 121 : case GNUNET_CRYPTO_BSA_CS:
919 121 : GNUNET_memcpy (out,
920 : &bs->details.blinded_cs_answer,
921 : sz);
922 121 : break;
923 0 : default:
924 0 : GNUNET_assert (0);
925 : }
926 217 : break;
927 : }
928 0 : case TALER_PQ_array_of_blinded_coin_hash:
929 : {
930 0 : const struct TALER_BlindedCoinHashP *coin_hs = data;
931 :
932 0 : GNUNET_memcpy (out,
933 : &coin_hs[i],
934 : sizeof(struct TALER_BlindedCoinHashP));
935 :
936 0 : break;
937 : }
938 0 : case TALER_PQ_array_of_denom_hash:
939 : {
940 0 : const struct TALER_DenominationHashP *denom_hs = data;
941 :
942 0 : GNUNET_memcpy (out,
943 : &denom_hs[i],
944 : sizeof(struct TALER_DenominationHashP));
945 0 : break;
946 : }
947 2 : case TALER_PQ_array_of_hash_code:
948 : {
949 2 : const struct GNUNET_HashCode *hashes = data;
950 :
951 2 : GNUNET_memcpy (out,
952 : &hashes[i],
953 : sizeof(struct GNUNET_HashCode));
954 2 : break;
955 : }
956 105 : case TALER_PQ_array_of_cs_r_pub:
957 : {
958 105 : const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
959 :
960 105 : GNUNET_memcpy (out,
961 : &cs_r_pubs[i],
962 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
963 105 : break;
964 : }
965 0 : default:
966 : {
967 0 : GNUNET_assert (0);
968 : break;
969 : }
970 : }
971 903 : out += sz;
972 : }
973 : }
974 824 : param_values[0] = elements;
975 824 : param_lengths[0] = total_size;
976 824 : param_formats[0] = 1;
977 824 : scratch[0] = elements;
978 :
979 824 : DONE:
980 824 : if (NULL != buffers)
981 : {
982 339 : for (size_t i = 0; i<num; i++)
983 217 : GNUNET_free (buffers[i]);
984 122 : GNUNET_free (buffers);
985 : }
986 824 : GNUNET_free (buffer_lengths);
987 824 : if (noerror)
988 824 : return 1;
989 0 : 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 824 : 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 824 : struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
1018 :
1019 824 : meta->typ = typ;
1020 824 : meta->oid = oid;
1021 824 : meta->sizes = sizes;
1022 824 : meta->same_size = same_size;
1023 824 : meta->continuous = continuous;
1024 824 : meta->db = db;
1025 :
1026 : {
1027 824 : 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 824 : return res;
1037 : }
1038 : }
1039 :
1040 :
1041 : struct GNUNET_PQ_QueryParam
1042 122 : 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 122 : GNUNET_assert (GNUNET_OK ==
1050 : GNUNET_PQ_get_oid_by_name (db,
1051 : "bytea",
1052 : &oid));
1053 122 : 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 0 : 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 0 : GNUNET_assert (GNUNET_OK ==
1073 : GNUNET_PQ_get_oid_by_name (db,
1074 : "bytea",
1075 : &oid));
1076 0 : 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 0 : 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 0 : GNUNET_assert (GNUNET_OK ==
1096 : GNUNET_PQ_get_oid_by_name (db,
1097 : "bytea",
1098 : &oid));
1099 0 : 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 1 : 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 1 : GNUNET_assert (GNUNET_OK ==
1118 : GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
1119 1 : 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 644 : 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 644 : GNUNET_assert (GNUNET_OK ==
1139 : GNUNET_PQ_get_oid_by_name (db,
1140 : "taler_amount",
1141 : &oid));
1142 644 : 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 1 : 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 1 : if (NULL != schema)
1165 1 : GNUNET_asprintf (&tn,
1166 : "%s.taler_amount_currency",
1167 : schema);
1168 : else
1169 0 : GNUNET_asprintf (&tn,
1170 : "taler_amount_currency");
1171 1 : GNUNET_assert (GNUNET_OK ==
1172 : GNUNET_PQ_get_oid_by_name (db,
1173 : tn,
1174 : &oid));
1175 1 : GNUNET_free (tn);
1176 1 : 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 56 : 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 56 : GNUNET_assert (GNUNET_OK ==
1197 : GNUNET_PQ_get_oid_by_name (db,
1198 : "bytea",
1199 : &oid));
1200 56 : 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 */
|