Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file pq/pq_result_helper.c
18 : * @brief functions to initialize parameter arrays
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include "taler_pq_lib.h"
24 :
25 :
26 : /**
27 : * Extract a currency amount from a query result according to the
28 : * given specification.
29 : *
30 : * @param result the result to extract the amount from
31 : * @param row which row of the result to extract the amount from (needed as results can have multiple rows)
32 : * @param currency currency to use for @a r_amount_nbo
33 : * @param val_name name of the column with the amount's "value", must include the substring "_val".
34 : * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac".
35 : * @param[out] r_amount_nbo where to store the amount, in network byte order
36 : * @return
37 : * #GNUNET_YES if all results could be extracted
38 : * #GNUNET_NO if at least one result was NULL
39 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
40 : */
41 : static enum GNUNET_GenericReturnValue
42 0 : extract_amount_nbo_helper (PGresult *result,
43 : int row,
44 : const char *currency,
45 : const char *val_name,
46 : const char *frac_name,
47 : struct TALER_AmountNBO *r_amount_nbo)
48 : {
49 : int val_num;
50 : int frac_num;
51 : int len;
52 :
53 : /* These checks are simply to check that clients obey by our naming
54 : conventions, and not for any functional reason */
55 0 : GNUNET_assert (NULL !=
56 : strstr (val_name,
57 : "_val"));
58 0 : GNUNET_assert (NULL !=
59 : strstr (frac_name,
60 : "_frac"));
61 : /* Set return value to invalid in case we don't finish */
62 0 : memset (r_amount_nbo,
63 : 0,
64 : sizeof (struct TALER_AmountNBO));
65 0 : val_num = PQfnumber (result,
66 : val_name);
67 0 : frac_num = PQfnumber (result,
68 : frac_name);
69 0 : if (val_num < 0)
70 : {
71 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
72 : "Field `%s' does not exist in result\n",
73 : val_name);
74 0 : return GNUNET_SYSERR;
75 : }
76 0 : if (frac_num < 0)
77 : {
78 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
79 : "Field `%s' does not exist in result\n",
80 : frac_name);
81 0 : return GNUNET_SYSERR;
82 : }
83 0 : if ( (PQgetisnull (result,
84 : row,
85 0 : val_num)) ||
86 0 : (PQgetisnull (result,
87 : row,
88 : frac_num)) )
89 : {
90 0 : return GNUNET_NO;
91 : }
92 : /* Note that Postgres stores value in NBO internally,
93 : so no conversion needed in this case */
94 0 : r_amount_nbo->value = *(uint64_t *) PQgetvalue (result,
95 : row,
96 : val_num);
97 0 : r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result,
98 : row,
99 : frac_num);
100 0 : if (GNUNET_ntohll (r_amount_nbo->value) >= TALER_AMOUNT_MAX_VALUE)
101 : {
102 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103 : "Field `%s' exceeds legal range\n",
104 : val_name);
105 0 : return GNUNET_SYSERR;
106 : }
107 0 : if (ntohl (r_amount_nbo->fraction) >= TALER_AMOUNT_FRAC_BASE)
108 : {
109 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
110 : "Field `%s' exceeds legal range\n",
111 : frac_name);
112 0 : return GNUNET_SYSERR;
113 : }
114 0 : len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
115 : strlen (currency));
116 0 : memcpy (r_amount_nbo->currency,
117 : currency,
118 : len);
119 0 : return GNUNET_OK;
120 : }
121 :
122 :
123 : /**
124 : * Extract data from a Postgres database @a result at row @a row.
125 : *
126 : * @param cls closure, a `const char *` giving the currency
127 : * @param result where to extract data from
128 : * @param row row to extract data from
129 : * @param fname name (or prefix) of the fields to extract from
130 : * @param[in,out] dst_size where to store size of result, may be NULL
131 : * @param[out] dst where to store the result
132 : * @return
133 : * #GNUNET_YES if all results could be extracted
134 : * #GNUNET_NO if at least one result was NULL
135 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
136 : */
137 : static enum GNUNET_GenericReturnValue
138 0 : extract_amount_nbo (void *cls,
139 : PGresult *result,
140 : int row,
141 : const char *fname,
142 : size_t *dst_size,
143 : void *dst)
144 : {
145 0 : const char *currency = cls;
146 : char *val_name;
147 : char *frac_name;
148 : enum GNUNET_GenericReturnValue ret;
149 :
150 0 : if (sizeof (struct TALER_AmountNBO) != *dst_size)
151 : {
152 0 : GNUNET_break (0);
153 0 : return GNUNET_SYSERR;
154 : }
155 0 : GNUNET_asprintf (&val_name,
156 : "%s_val",
157 : fname);
158 0 : GNUNET_asprintf (&frac_name,
159 : "%s_frac",
160 : fname);
161 0 : ret = extract_amount_nbo_helper (result,
162 : row,
163 : currency,
164 : val_name,
165 : frac_name,
166 : dst);
167 0 : GNUNET_free (val_name);
168 0 : GNUNET_free (frac_name);
169 0 : return ret;
170 : }
171 :
172 :
173 : struct GNUNET_PQ_ResultSpec
174 0 : TALER_PQ_result_spec_amount_nbo (const char *name,
175 : const char *currency,
176 : struct TALER_AmountNBO *amount)
177 : {
178 0 : struct GNUNET_PQ_ResultSpec res = {
179 : .conv = &extract_amount_nbo,
180 : .cls = (void *) currency,
181 : .dst = (void *) amount,
182 : .dst_size = sizeof (*amount),
183 : .fname = name
184 : };
185 :
186 0 : return res;
187 : }
188 :
189 :
190 : /**
191 : * Extract data from a Postgres database @a result at row @a row.
192 : *
193 : * @param cls closure, a `const char *` giving the currency
194 : * @param result where to extract data from
195 : * @param row row to extract data from
196 : * @param fname name (or prefix) of the fields to extract from
197 : * @param[in,out] dst_size where to store size of result, may be NULL
198 : * @param[out] dst where to store the result
199 : * @return
200 : * #GNUNET_YES if all results could be extracted
201 : * #GNUNET_NO if at least one result was NULL
202 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
203 : */
204 : static enum GNUNET_GenericReturnValue
205 0 : extract_amount (void *cls,
206 : PGresult *result,
207 : int row,
208 : const char *fname,
209 : size_t *dst_size,
210 : void *dst)
211 : {
212 0 : const char *currency = cls;
213 0 : struct TALER_Amount *r_amount = dst;
214 : char *val_name;
215 : char *frac_name;
216 : struct TALER_AmountNBO amount_nbo;
217 : enum GNUNET_GenericReturnValue ret;
218 :
219 0 : if (sizeof (struct TALER_AmountNBO) != *dst_size)
220 : {
221 0 : GNUNET_break (0);
222 0 : return GNUNET_SYSERR;
223 : }
224 0 : GNUNET_asprintf (&val_name,
225 : "%s_val",
226 : fname);
227 0 : GNUNET_asprintf (&frac_name,
228 : "%s_frac",
229 : fname);
230 0 : ret = extract_amount_nbo_helper (result,
231 : row,
232 : currency,
233 : val_name,
234 : frac_name,
235 : &amount_nbo);
236 0 : if (GNUNET_OK == ret)
237 0 : TALER_amount_ntoh (r_amount,
238 : &amount_nbo);
239 : else
240 0 : memset (r_amount,
241 : 0,
242 : sizeof (struct TALER_Amount));
243 0 : GNUNET_free (val_name);
244 0 : GNUNET_free (frac_name);
245 0 : return ret;
246 : }
247 :
248 :
249 : struct GNUNET_PQ_ResultSpec
250 0 : TALER_PQ_result_spec_amount (const char *name,
251 : const char *currency,
252 : struct TALER_Amount *amount)
253 : {
254 0 : struct GNUNET_PQ_ResultSpec res = {
255 : .conv = &extract_amount,
256 : .cls = (void *) currency,
257 : .dst = (void *) amount,
258 : .dst_size = sizeof (*amount),
259 : .fname = name
260 : };
261 :
262 0 : return res;
263 : }
264 :
265 :
266 : /**
267 : * Extract data from a Postgres database @a result at row @a row.
268 : *
269 : * @param cls closure
270 : * @param result where to extract data from
271 : * @param row row to extract data from
272 : * @param fname name (or prefix) of the fields to extract from
273 : * @param[in,out] dst_size where to store size of result, may be NULL
274 : * @param[out] dst where to store the result
275 : * @return
276 : * #GNUNET_YES if all results could be extracted
277 : * #GNUNET_NO if at least one result was NULL
278 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
279 : */
280 : static enum GNUNET_GenericReturnValue
281 0 : extract_json (void *cls,
282 : PGresult *result,
283 : int row,
284 : const char *fname,
285 : size_t *dst_size,
286 : void *dst)
287 : {
288 0 : json_t **j_dst = dst;
289 : const char *res;
290 : int fnum;
291 : json_error_t json_error;
292 : size_t slen;
293 :
294 : (void) cls;
295 : (void) dst_size;
296 0 : fnum = PQfnumber (result,
297 : fname);
298 0 : if (fnum < 0)
299 : {
300 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301 : "Field `%s' does not exist in result\n",
302 : fname);
303 0 : return GNUNET_SYSERR;
304 : }
305 0 : if (PQgetisnull (result,
306 : row,
307 : fnum))
308 0 : return GNUNET_NO;
309 0 : slen = PQgetlength (result,
310 : row,
311 : fnum);
312 0 : res = (const char *) PQgetvalue (result,
313 : row,
314 : fnum);
315 0 : *j_dst = json_loadb (res,
316 : slen,
317 : JSON_REJECT_DUPLICATES,
318 : &json_error);
319 0 : if (NULL == *j_dst)
320 : {
321 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322 : "Failed to parse JSON result for field `%s': %s (%s)\n",
323 : fname,
324 : json_error.text,
325 : json_error.source);
326 0 : return GNUNET_SYSERR;
327 : }
328 0 : return GNUNET_OK;
329 : }
330 :
331 :
332 : /**
333 : * Function called to clean up memory allocated
334 : * by a #GNUNET_PQ_ResultConverter.
335 : *
336 : * @param cls closure
337 : * @param rd result data to clean up
338 : */
339 : static void
340 0 : clean_json (void *cls,
341 : void *rd)
342 : {
343 0 : json_t **dst = rd;
344 :
345 : (void) cls;
346 0 : if (NULL != *dst)
347 : {
348 0 : json_decref (*dst);
349 0 : *dst = NULL;
350 : }
351 0 : }
352 :
353 :
354 : struct GNUNET_PQ_ResultSpec
355 0 : TALER_PQ_result_spec_json (const char *name,
356 : json_t **jp)
357 : {
358 0 : struct GNUNET_PQ_ResultSpec res = {
359 : .conv = &extract_json,
360 : .cleaner = &clean_json,
361 : .dst = (void *) jp,
362 : .fname = name
363 : };
364 :
365 0 : return res;
366 : }
367 :
368 :
369 : /**
370 : * Extract data from a Postgres database @a result at row @a row.
371 : *
372 : * @param cls closure
373 : * @param result where to extract data from
374 : * @param row the row to extract data from
375 : * @param fname name (or prefix) of the fields to extract from
376 : * @param[in,out] dst_size where to store size of result, may be NULL
377 : * @param[out] dst where to store the result
378 : * @return
379 : * #GNUNET_YES if all results could be extracted
380 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
381 : */
382 : static enum GNUNET_GenericReturnValue
383 0 : extract_denom_pub (void *cls,
384 : PGresult *result,
385 : int row,
386 : const char *fname,
387 : size_t *dst_size,
388 : void *dst)
389 : {
390 0 : struct TALER_DenominationPublicKey *pk = dst;
391 : size_t len;
392 : const char *res;
393 : int fnum;
394 : uint32_t be[2];
395 :
396 : (void) cls;
397 : (void) dst_size;
398 0 : fnum = PQfnumber (result,
399 : fname);
400 0 : if (fnum < 0)
401 : {
402 0 : GNUNET_break (0);
403 0 : return GNUNET_SYSERR;
404 : }
405 0 : if (PQgetisnull (result,
406 : row,
407 : fnum))
408 0 : return GNUNET_NO;
409 :
410 : /* if a field is null, continue but
411 : * remember that we now return a different result */
412 0 : len = PQgetlength (result,
413 : row,
414 : fnum);
415 0 : res = PQgetvalue (result,
416 : row,
417 : fnum);
418 0 : if (len < sizeof (be))
419 : {
420 0 : GNUNET_break (0);
421 0 : return GNUNET_SYSERR;
422 : }
423 0 : memcpy (be,
424 : res,
425 : sizeof (be));
426 0 : res += sizeof (be);
427 0 : len -= sizeof (be);
428 0 : pk->cipher = ntohl (be[0]);
429 0 : pk->age_mask.bits = ntohl (be[1]);
430 0 : switch (pk->cipher)
431 : {
432 0 : case TALER_DENOMINATION_RSA:
433 : pk->details.rsa_public_key
434 0 : = GNUNET_CRYPTO_rsa_public_key_decode (res,
435 : len);
436 0 : if (NULL == pk->details.rsa_public_key)
437 : {
438 0 : GNUNET_break (0);
439 0 : return GNUNET_SYSERR;
440 : }
441 0 : return GNUNET_OK;
442 0 : case TALER_DENOMINATION_CS:
443 0 : if (sizeof (pk->details.cs_public_key) != len)
444 : {
445 0 : GNUNET_break (0);
446 0 : return GNUNET_SYSERR;
447 : }
448 0 : memcpy (&pk->details.cs_public_key,
449 : res,
450 : len);
451 0 : return GNUNET_OK;
452 0 : default:
453 0 : GNUNET_break (0);
454 : }
455 0 : return GNUNET_SYSERR;
456 : }
457 :
458 :
459 : /**
460 : * Function called to clean up memory allocated
461 : * by a #GNUNET_PQ_ResultConverter.
462 : *
463 : * @param cls closure
464 : * @param rd result data to clean up
465 : */
466 : static void
467 0 : clean_denom_pub (void *cls,
468 : void *rd)
469 : {
470 0 : struct TALER_DenominationPublicKey *denom_pub = rd;
471 :
472 : (void) cls;
473 0 : TALER_denom_pub_free (denom_pub);
474 0 : }
475 :
476 :
477 : struct GNUNET_PQ_ResultSpec
478 0 : TALER_PQ_result_spec_denom_pub (const char *name,
479 : struct TALER_DenominationPublicKey *denom_pub)
480 : {
481 0 : struct GNUNET_PQ_ResultSpec res = {
482 : .conv = &extract_denom_pub,
483 : .cleaner = &clean_denom_pub,
484 : .dst = (void *) denom_pub,
485 : .fname = name
486 : };
487 :
488 0 : return res;
489 : }
490 :
491 :
492 : /**
493 : * Extract data from a Postgres database @a result at row @a row.
494 : *
495 : * @param cls closure
496 : * @param result where to extract data from
497 : * @param row the row to extract data from
498 : * @param fname name (or prefix) of the fields to extract from
499 : * @param[in,out] dst_size where to store size of result, may be NULL
500 : * @param[out] dst where to store the result
501 : * @return
502 : * #GNUNET_YES if all results could be extracted
503 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
504 : */
505 : static enum GNUNET_GenericReturnValue
506 0 : extract_denom_sig (void *cls,
507 : PGresult *result,
508 : int row,
509 : const char *fname,
510 : size_t *dst_size,
511 : void *dst)
512 : {
513 0 : struct TALER_DenominationSignature *sig = dst;
514 : size_t len;
515 : const char *res;
516 : int fnum;
517 : uint32_t be[2];
518 :
519 : (void) cls;
520 : (void) dst_size;
521 0 : fnum = PQfnumber (result,
522 : fname);
523 0 : if (fnum < 0)
524 : {
525 0 : GNUNET_break (0);
526 0 : return GNUNET_SYSERR;
527 : }
528 0 : if (PQgetisnull (result,
529 : row,
530 : fnum))
531 0 : return GNUNET_NO;
532 :
533 : /* if a field is null, continue but
534 : * remember that we now return a different result */
535 0 : len = PQgetlength (result,
536 : row,
537 : fnum);
538 0 : res = PQgetvalue (result,
539 : row,
540 : fnum);
541 0 : if (len < sizeof (be))
542 : {
543 0 : GNUNET_break (0);
544 0 : return GNUNET_SYSERR;
545 : }
546 0 : memcpy (&be,
547 : res,
548 : sizeof (be));
549 0 : if (0x00 != ntohl (be[1]))
550 : {
551 0 : GNUNET_break (0);
552 0 : return GNUNET_SYSERR;
553 : }
554 0 : res += sizeof (be);
555 0 : len -= sizeof (be);
556 0 : sig->cipher = ntohl (be[0]);
557 0 : switch (sig->cipher)
558 : {
559 0 : case TALER_DENOMINATION_RSA:
560 : sig->details.rsa_signature
561 0 : = GNUNET_CRYPTO_rsa_signature_decode (res,
562 : len);
563 0 : if (NULL == sig->details.rsa_signature)
564 : {
565 0 : GNUNET_break (0);
566 0 : return GNUNET_SYSERR;
567 : }
568 0 : return GNUNET_OK;
569 0 : case TALER_DENOMINATION_CS:
570 0 : if (sizeof (sig->details.cs_signature) != len)
571 : {
572 0 : GNUNET_break (0);
573 0 : return GNUNET_SYSERR;
574 : }
575 0 : memcpy (&sig->details.cs_signature,
576 : res,
577 : len);
578 0 : return GNUNET_OK;
579 0 : default:
580 0 : GNUNET_break (0);
581 : }
582 0 : return GNUNET_SYSERR;
583 : }
584 :
585 :
586 : /**
587 : * Function called to clean up memory allocated
588 : * by a #GNUNET_PQ_ResultConverter.
589 : *
590 : * @param cls closure
591 : * @param rd result data to clean up
592 : */
593 : static void
594 0 : clean_denom_sig (void *cls,
595 : void *rd)
596 : {
597 0 : struct TALER_DenominationSignature *denom_sig = rd;
598 :
599 : (void) cls;
600 0 : TALER_denom_sig_free (denom_sig);
601 0 : }
602 :
603 :
604 : struct GNUNET_PQ_ResultSpec
605 0 : TALER_PQ_result_spec_denom_sig (const char *name,
606 : struct TALER_DenominationSignature *denom_sig)
607 : {
608 0 : struct GNUNET_PQ_ResultSpec res = {
609 : .conv = &extract_denom_sig,
610 : .cleaner = &clean_denom_sig,
611 : .dst = (void *) denom_sig,
612 : .fname = name
613 : };
614 :
615 0 : return res;
616 : }
617 :
618 :
619 : /**
620 : * Extract data from a Postgres database @a result at row @a row.
621 : *
622 : * @param cls closure
623 : * @param result where to extract data from
624 : * @param row the row to extract data from
625 : * @param fname name (or prefix) of the fields to extract from
626 : * @param[in,out] dst_size where to store size of result, may be NULL
627 : * @param[out] dst where to store the result
628 : * @return
629 : * #GNUNET_YES if all results could be extracted
630 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
631 : */
632 : static enum GNUNET_GenericReturnValue
633 0 : extract_blinded_denom_sig (void *cls,
634 : PGresult *result,
635 : int row,
636 : const char *fname,
637 : size_t *dst_size,
638 : void *dst)
639 : {
640 0 : struct TALER_BlindedDenominationSignature *sig = dst;
641 : size_t len;
642 : const char *res;
643 : int fnum;
644 : uint32_t be[2];
645 :
646 : (void) cls;
647 : (void) dst_size;
648 0 : fnum = PQfnumber (result,
649 : fname);
650 0 : if (fnum < 0)
651 : {
652 0 : GNUNET_break (0);
653 0 : return GNUNET_SYSERR;
654 : }
655 0 : if (PQgetisnull (result,
656 : row,
657 : fnum))
658 0 : return GNUNET_NO;
659 :
660 : /* if a field is null, continue but
661 : * remember that we now return a different result */
662 0 : len = PQgetlength (result,
663 : row,
664 : fnum);
665 0 : res = PQgetvalue (result,
666 : row,
667 : fnum);
668 0 : if (len < sizeof (be))
669 : {
670 0 : GNUNET_break (0);
671 0 : return GNUNET_SYSERR;
672 : }
673 0 : memcpy (&be,
674 : res,
675 : sizeof (be));
676 0 : if (0x01 != ntohl (be[1])) /* magic marker: blinded */
677 : {
678 0 : GNUNET_break (0);
679 0 : return GNUNET_SYSERR;
680 : }
681 0 : res += sizeof (be);
682 0 : len -= sizeof (be);
683 0 : sig->cipher = ntohl (be[0]);
684 0 : switch (sig->cipher)
685 : {
686 0 : case TALER_DENOMINATION_RSA:
687 : sig->details.blinded_rsa_signature
688 0 : = GNUNET_CRYPTO_rsa_signature_decode (res,
689 : len);
690 0 : if (NULL == sig->details.blinded_rsa_signature)
691 : {
692 0 : GNUNET_break (0);
693 0 : return GNUNET_SYSERR;
694 : }
695 0 : return GNUNET_OK;
696 0 : case TALER_DENOMINATION_CS:
697 0 : if (sizeof (sig->details.blinded_cs_answer) != len)
698 : {
699 0 : GNUNET_break (0);
700 0 : return GNUNET_SYSERR;
701 : }
702 0 : memcpy (&sig->details.blinded_cs_answer,
703 : res,
704 : len);
705 0 : return GNUNET_OK;
706 0 : default:
707 0 : GNUNET_break (0);
708 : }
709 0 : return GNUNET_SYSERR;
710 : }
711 :
712 :
713 : /**
714 : * Function called to clean up memory allocated
715 : * by a #GNUNET_PQ_ResultConverter.
716 : *
717 : * @param cls closure
718 : * @param rd result data to clean up
719 : */
720 : static void
721 0 : clean_blinded_denom_sig (void *cls,
722 : void *rd)
723 : {
724 0 : struct TALER_BlindedDenominationSignature *denom_sig = rd;
725 :
726 : (void) cls;
727 0 : TALER_blinded_denom_sig_free (denom_sig);
728 0 : }
729 :
730 :
731 : struct GNUNET_PQ_ResultSpec
732 0 : TALER_PQ_result_spec_blinded_denom_sig (
733 : const char *name,
734 : struct TALER_BlindedDenominationSignature *denom_sig)
735 : {
736 0 : struct GNUNET_PQ_ResultSpec res = {
737 : .conv = &extract_blinded_denom_sig,
738 : .cleaner = &clean_blinded_denom_sig,
739 : .dst = (void *) denom_sig,
740 : .fname = name
741 : };
742 :
743 0 : return res;
744 : }
745 :
746 :
747 : /**
748 : * Extract data from a Postgres database @a result at row @a row.
749 : *
750 : * @param cls closure
751 : * @param result where to extract data from
752 : * @param row the row to extract data from
753 : * @param fname name (or prefix) of the fields to extract from
754 : * @param[in,out] dst_size where to store size of result, may be NULL
755 : * @param[out] dst where to store the result
756 : * @return
757 : * #GNUNET_YES if all results could be extracted
758 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
759 : */
760 : static enum GNUNET_GenericReturnValue
761 0 : extract_blinded_planchet (void *cls,
762 : PGresult *result,
763 : int row,
764 : const char *fname,
765 : size_t *dst_size,
766 : void *dst)
767 : {
768 0 : struct TALER_BlindedPlanchet *bp = dst;
769 : size_t len;
770 : const char *res;
771 : int fnum;
772 : uint32_t be[2];
773 :
774 : (void) cls;
775 : (void) dst_size;
776 0 : fnum = PQfnumber (result,
777 : fname);
778 0 : if (fnum < 0)
779 : {
780 0 : GNUNET_break (0);
781 0 : return GNUNET_SYSERR;
782 : }
783 0 : if (PQgetisnull (result,
784 : row,
785 : fnum))
786 0 : return GNUNET_NO;
787 :
788 : /* if a field is null, continue but
789 : * remember that we now return a different result */
790 0 : len = PQgetlength (result,
791 : row,
792 : fnum);
793 0 : res = PQgetvalue (result,
794 : row,
795 : fnum);
796 0 : if (len < sizeof (be))
797 : {
798 0 : GNUNET_break (0);
799 0 : return GNUNET_SYSERR;
800 : }
801 0 : memcpy (&be,
802 : res,
803 : sizeof (be));
804 0 : if (0x0100 != ntohl (be[1])) /* magic marker: blinded */
805 : {
806 0 : GNUNET_break (0);
807 0 : return GNUNET_SYSERR;
808 : }
809 0 : res += sizeof (be);
810 0 : len -= sizeof (be);
811 0 : bp->cipher = ntohl (be[0]);
812 0 : switch (bp->cipher)
813 : {
814 0 : case TALER_DENOMINATION_RSA:
815 : bp->details.rsa_blinded_planchet.blinded_msg_size
816 0 : = len;
817 : bp->details.rsa_blinded_planchet.blinded_msg
818 0 : = GNUNET_memdup (res,
819 : len);
820 0 : return GNUNET_OK;
821 0 : case TALER_DENOMINATION_CS:
822 0 : if (sizeof (bp->details.cs_blinded_planchet) != len)
823 : {
824 0 : GNUNET_break (0);
825 0 : return GNUNET_SYSERR;
826 : }
827 0 : memcpy (&bp->details.cs_blinded_planchet,
828 : res,
829 : len);
830 0 : return GNUNET_OK;
831 0 : default:
832 0 : GNUNET_break (0);
833 : }
834 0 : return GNUNET_SYSERR;
835 : }
836 :
837 :
838 : /**
839 : * Function called to clean up memory allocated
840 : * by a #GNUNET_PQ_ResultConverter.
841 : *
842 : * @param cls closure
843 : * @param rd result data to clean up
844 : */
845 : static void
846 0 : clean_blinded_planchet (void *cls,
847 : void *rd)
848 : {
849 0 : struct TALER_BlindedPlanchet *bp = rd;
850 :
851 : (void) cls;
852 0 : TALER_blinded_planchet_free (bp);
853 0 : }
854 :
855 :
856 : struct GNUNET_PQ_ResultSpec
857 0 : TALER_PQ_result_spec_blinded_planchet (
858 : const char *name,
859 : struct TALER_BlindedPlanchet *bp)
860 : {
861 0 : struct GNUNET_PQ_ResultSpec res = {
862 : .conv = &extract_blinded_planchet,
863 : .cleaner = &clean_blinded_planchet,
864 : .dst = (void *) bp,
865 : .fname = name
866 : };
867 :
868 0 : return res;
869 : }
870 :
871 :
872 : /**
873 : * Extract data from a Postgres database @a result at row @a row.
874 : *
875 : * @param cls closure
876 : * @param result where to extract data from
877 : * @param row row to extract data from
878 : * @param fname name (or prefix) of the fields to extract from
879 : * @param[in,out] dst_size where to store size of result, may be NULL
880 : * @param[out] dst where to store the result
881 : * @return
882 : * #GNUNET_YES if all results could be extracted
883 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
884 : */
885 : static enum GNUNET_GenericReturnValue
886 0 : extract_exchange_withdraw_values (void *cls,
887 : PGresult *result,
888 : int row,
889 : const char *fname,
890 : size_t *dst_size,
891 : void *dst)
892 : {
893 0 : struct TALER_ExchangeWithdrawValues *alg_values = dst;
894 : size_t len;
895 : const char *res;
896 : int fnum;
897 : uint32_t be[2];
898 :
899 : (void) cls;
900 : (void) dst_size;
901 0 : fnum = PQfnumber (result,
902 : fname);
903 0 : if (fnum < 0)
904 : {
905 0 : GNUNET_break (0);
906 0 : return GNUNET_SYSERR;
907 : }
908 0 : if (PQgetisnull (result,
909 : row,
910 : fnum))
911 0 : return GNUNET_NO;
912 :
913 : /* if a field is null, continue but
914 : * remember that we now return a different result */
915 0 : len = PQgetlength (result,
916 : row,
917 : fnum);
918 0 : res = PQgetvalue (result,
919 : row,
920 : fnum);
921 0 : if (len < sizeof (be))
922 : {
923 0 : GNUNET_break (0);
924 0 : return GNUNET_SYSERR;
925 : }
926 0 : memcpy (&be,
927 : res,
928 : sizeof (be));
929 0 : if (0x010000 != ntohl (be[1])) /* magic marker: EWV */
930 : {
931 0 : GNUNET_break (0);
932 0 : return GNUNET_SYSERR;
933 : }
934 0 : res += sizeof (be);
935 0 : len -= sizeof (be);
936 0 : alg_values->cipher = ntohl (be[0]);
937 0 : switch (alg_values->cipher)
938 : {
939 0 : case TALER_DENOMINATION_RSA:
940 0 : if (0 != len)
941 : {
942 0 : GNUNET_break (0);
943 0 : return GNUNET_SYSERR;
944 : }
945 0 : return GNUNET_OK;
946 0 : case TALER_DENOMINATION_CS:
947 0 : if (sizeof (struct TALER_DenominationCSPublicRPairP) != len)
948 : {
949 0 : GNUNET_break (0);
950 0 : return GNUNET_SYSERR;
951 : }
952 0 : memcpy (&alg_values->details.cs_values,
953 : res,
954 : len);
955 0 : return GNUNET_OK;
956 0 : default:
957 0 : GNUNET_break (0);
958 : }
959 0 : return GNUNET_SYSERR;
960 : }
961 :
962 :
963 : struct GNUNET_PQ_ResultSpec
964 0 : TALER_PQ_result_spec_exchange_withdraw_values (
965 : const char *name,
966 : struct TALER_ExchangeWithdrawValues *ewv)
967 : {
968 0 : struct GNUNET_PQ_ResultSpec res = {
969 : .conv = &extract_exchange_withdraw_values,
970 : .dst = (void *) ewv,
971 : .fname = name
972 : };
973 :
974 0 : return res;
975 : }
976 :
977 :
978 : /* end of pq_result_helper.c */
|