LCOV - code coverage report
Current view: top level - pq - pq_result_helper.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 55.9 % 601 336
Test Date: 2026-01-09 13:26:54 Functions: 66.7 % 30 20

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

Generated by: LCOV version 2.0-1