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:
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"