LCOV - code coverage report
Current view: top level - pq - pq_result_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 307 563 54.5 %
Date: 2025-06-05 21:03:14 Functions: 20 29 69.0 %

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

Generated by: LCOV version 1.16