donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 59af47bfc918848cef2468c3f96514513f4d8daf
parent 8772094f2c017892e4f914eed29458ff022ea699
Author: Casaburi Johannes <johannes.casaburi@students.bfh.ch>
Date:   Tue, 19 Dec 2023 11:20:09 +0100

[db] working on query helper

Diffstat:
Asrc/pq/pq_common.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/pq/pq_query_helper.c | 277+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testing/donau-unified-setup.sh | 2+-
3 files changed, 326 insertions(+), 1 deletion(-)

diff --git a/src/pq/pq_common.h b/src/pq/pq_common.h @@ -0,0 +1,48 @@ +/* + This file is part of TALER + Copyright (C) 2023 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file pq/pq_common.h + * @brief common defines for the pq functions + * @author Johannes Casaburi + */ +#ifndef DONAU_PQ_COMMON_H_ +#define DONAU_PQ_COMMON_H_ + +#include "taler/taler_util.h" + +/** + * Internal types that are supported as DONAU-exchange-specific array types. + * + * To support a new type, + * 1. add a new entry into this list, + * 2. for query-support, implement the size calculation and memory copying in + * qconv_array() accordingly, in pq_query_helper.c + * 3. provide a query-API for arrays of the type, by calling + * query_param_array_generic with the appropriate parameters, + * in pq_query_helper.c + * 4. for result-support, implement memory copying by adding another case + * to extract_array_generic, in pq_result_helper.c + * 5. provide a result-spec-API for arrays of the type, + * in pq_result_helper.c + * 6. expose the API's in taler_pq_lib.h + */ +enum DONAU_PQ_ArrayType +{ + DONAU_PQ_array_of_blinded_donation_id_kps, +}; + +#endif /* TALER_PQ_COMMON_H_ */ +/* end of pg/pq_common.h */ diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c @@ -23,6 +23,7 @@ #include <gnunet/gnunet_pq_lib.h> #include <taler/taler_pq_lib.h> #include "donau_util.h" +#include "pq_common.h" /** @@ -122,4 +123,280 @@ TALER_PQ_query_param_donation_unit_pub ( } +/** ------------------- Array support -----------------------------------**/ + +/** + * Closure for the array type handlers. + * + * May contain sizes information for the data, given (and handled) by the + * caller. + */ +struct qconv_array_cls +{ + /** + * If not null, contains the array of sizes (the size of the array is the + * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free + * this memory. + * + * If not null, this value has precedence over @a sizes, which MUST be NULL */ + const size_t *sizes; + + /** + * If @a size and @a c_sizes are NULL, this field defines the same size + * for each element in the array. + */ + size_t same_size; + + /** + * If true, the array parameter to the data pointer to the qconv_array is a + * continuous byte array of data, either with @a same_size each or sizes + * provided bytes by @a sizes; + */ + bool continuous; + + /** + * Type of the array elements + */ + enum DONAU_PQ_ArrayType typ; + + /** + * Oid of the array elements + */ + Oid oid; + + /** + * db context, needed for OID-lookup of basis-types + */ + struct GNUNET_PQ_Context *db; +}; + +/** + * Callback to cleanup a qconv_array_cls to be used during + * GNUNET_PQ_cleanup_query_params_closures + */ +static void +qconv_array_cls_cleanup (void *cls) +{ + GNUNET_free (cls); +} + + +/** + * Function called to convert input argument into SQL parameters for arrays + * + * Note: the format for the encoding of arrays for libpq is not very well + * documented. We peeked into various sources (postgresql and libpqtypes) for + * guidance. + * + * @param cls Closure of type struct qconv_array_cls* + * @param data Pointer to first element in the array + * @param data_len Number of _elements_ in array @a data (if applicable) + * @param[out] param_values SQL data to set + * @param[out] param_lengths SQL length data to set + * @param[out] param_formats SQL format data to set + * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays + * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() + * @param scratch_length number of entries left in @a scratch + * @return -1 on error, number of offsets used in @a scratch otherwise + */ +static int +qconv_array ( + void *cls, + const void *data, + size_t data_len, + void *param_values[], + int param_lengths[], + int param_formats[], + unsigned int param_length, + void *scratch[], + unsigned int scratch_length) +{ + struct qconv_array_cls *meta = cls; + size_t num = data_len; + size_t tlen; + size_t total_size; + const size_t *sizes; + bool same_sized; + void *elements = NULL; + bool noerror = true; + /* needed to capture the encoded rsa signatures */ + void **buffers = NULL; + size_t *buffer_lengths = NULL; + + (void) (param_length); + (void) (scratch_length); + + GNUNET_assert (NULL != meta); + GNUNET_assert (num < INT_MAX); + + sizes = meta->sizes; + same_sized = (0 != meta->same_size); + +#define RETURN_UNLESS(cond) \ + do { \ + if (! (cond)) \ + { \ + GNUNET_break ((cond)); \ + noerror = false; \ + goto DONE; \ + } \ + } while (0) + + /* Calculate sizes and check bounds */ + { + /* num * length-field */ + size_t x = sizeof(uint32_t); + size_t y = x * num; + RETURN_UNLESS ((0 == num) || (y / num == x)); + + /* size of header */ + total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P); + total_size += y; + RETURN_UNLESS (total_size >= x); + + /* sizes of elements */ + if (same_sized) + { + x = num * meta->same_size; + RETURN_UNLESS ((0 == num) || (x / num == meta->same_size)); + + y = total_size; + total_size += x; + RETURN_UNLESS (total_size >= y); + } + else /* sizes are different per element */ + { + switch (meta->typ) + { + case DONAU_PQ_array_of_blinded_donation_id_kps: + { + const struct DONAU_BlindedUniqueDonationIdentifierKeyPair *budi_kps = data; + size_t len; + + buffers = GNUNET_new_array (num, void *); + buffer_lengths = GNUNET_new_array (num, size_t); + + for (size_t i = 0; i<num; i++) + { + const struct GNUNET_CRYPTO_BlindedMessage *bm = &budi_kps[i].blinded_udi; + + switch (bm->cipher) //? + { + case GNUNET_CRYPTO_BSA_RSA: + tlen = bm->details.rsa_blinded_message.blinded_msg_size; + break; + case GNUNET_CRYPTO_BSA_CS: + tlen = sizeof (bm->details.cs_blinded_message); + break; + default: + GNUNET_assert (0); + } + + len = tlen + sizeof (bm); + buffer_lengths[i] = len; + + y = total_size; + total_size += len; + RETURN_UNLESS (total_size >= y); + } + sizes = buffer_lengths; + break; + } + default: + GNUNET_assert (0); + } + } + + RETURN_UNLESS (INT_MAX > total_size); + RETURN_UNLESS (0 != total_size); + + elements = GNUNET_malloc (total_size); + } + + /* Write data */ + { + char *out = elements; + struct GNUNET_PQ_ArrayHeader_P h = { + .ndim = htonl (1), /* We only support one-dimensional arrays */ + .has_null = htonl (0), /* We do not support NULL entries in arrays */ + .lbound = htonl (1), /* Default start index value */ + .dim = htonl (num), + .oid = htonl (meta->oid), + }; + + /* Write header */ + GNUNET_memcpy (out, + &h, + sizeof(h)); + out += sizeof(h); + + /* Write elements */ + for (size_t i = 0; i < num; i++) + { + size_t sz = same_sized ? meta->same_size : sizes[i]; + + *(uint32_t *) out = htonl (sz); + out += sizeof(uint32_t); + switch (meta->typ) + { + case DONAU_PQ_array_of_blinded_donation_id_kps: + { + const struct DONAU_BlindedUniqueDonationIdentifierKeyPair *budi_kps = data; + const struct GNUNET_CRYPTO_BlindedMessage *bm = &budi_kps[i].blinded_udi; + uint32_t be[2]; + + be[0] = htonl ((uint32_t) bm->cipher); + be[1] = htonl (0x01); /* magic margker: blinded */ + GNUNET_memcpy (out, + &be, + sizeof(be)); + out += sizeof(be); + sz -= sizeof(be); + + switch (bm->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + /* For RSA, 'same_sized' must have been false */ + GNUNET_assert (NULL != buffers); + GNUNET_memcpy (out, + buffers[i], + sz); + break; + case GNUNET_CRYPTO_BSA_CS: + GNUNET_memcpy (out, + &bm->details.cs_blinded_message, + sz); + break; + default: + GNUNET_assert (0); + } + break; + } + default: + { + GNUNET_assert (0); + break; + } + } + out += sz; + } + } + param_values[0] = elements; + param_lengths[0] = total_size; + param_formats[0] = 1; + scratch[0] = elements; + +DONE: + if (NULL != buffers) + { + for (size_t i = 0; i<num; i++) + GNUNET_free (buffers[i]); + GNUNET_free (buffers); + } + GNUNET_free (buffer_lengths); + if (noerror) + return 1; + return -1; +} + /* end of pq/pq_query_helper.c */ diff --git a/src/testing/donau-unified-setup.sh b/src/testing/donau-unified-setup.sh @@ -83,7 +83,7 @@ LOGLEVEL="DEBUG" DEFAULT_SLEEP="0.2" # Parse command-line options -while getopts ':abc:d:efghkL:mnr:stu:vwW' OPTION; do +while getopts ':abc:d:efghkL:mnr:stu:vwWD' OPTION; do case "$OPTION" in a) START_AUDITOR="1"