aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-10-04 11:33:21 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2022-10-04 11:33:21 +0200
commit3ec07d62c35f0e74ed53cb0712ccb446fe656728 (patch)
tree7929a5caba77df0f11b69445402feb1fd418b58d
parent424bbddaa36613eacccb18545128c8b1a4a11538 (diff)
improved error handling
-rw-r--r--src/extensions/auction_brandt/extension_auction_brandt.c302
1 files changed, 228 insertions, 74 deletions
diff --git a/src/extensions/auction_brandt/extension_auction_brandt.c b/src/extensions/auction_brandt/extension_auction_brandt.c
index 24ac452b..358c6b7c 100644
--- a/src/extensions/auction_brandt/extension_auction_brandt.c
+++ b/src/extensions/auction_brandt/extension_auction_brandt.c
@@ -33,6 +33,9 @@
/* Path to the replay program. */
static char *replay_program;
+/* supported currency */
+static char *currency;
+
/* This is basically BRANDT_Result with an extra string field */
struct result
{
@@ -42,28 +45,54 @@ struct result
};
/*
- * TODO: Transcript information
+ * @brief Transcript information
+ *
*/
struct transcript
{
- // All fields from json come here.
- uint16_t n; // #bidders + 1
- uint16_t k; // #prices
- uint16_t m; // type of auction
- struct GNUNET_TIME_Absolute time_start;
- struct GNUNET_TIME_Relative time_round;
+ /*
+ * The first couple of fields are from a JSON transcript
+ */
+
+ /* Public key of seller */
+ struct GNUNET_CRYPTO_EddsaPublicKey seller_pub;
+
+ /* Payto URL */
+ const char *payto;
+
+ /* Number of bidders + 1 (for seller) */
+ uint16_t n;
+
+ /* (n-1) public keys of bidders */
+ struct GNUNET_CRYPTO_EddsaPublicKey *bidder_pub;
+
+ /* Type of auction, see libbrandt */
+ uint16_t m;
+
+ /* Auction public outcome? */
bool public;
- char **prices; // Must be of length k. We do not parse those
- // struct msg *msgs; // Array must be of length 4*n
- // struct BRANDT_Auction *auction;
+ /* Start date of the auction */
+ struct GNUNET_TIME_Timestamp time_start;
- struct result *results;
- size_t results_len;
+ /* End date of the auction */
+ struct GNUNET_TIME_Relative time_round;
+
+ /* Number of prices */
+ uint16_t k;
+
+ /* Prices, must be length k */
+ struct TALER_Amount *prices;
+
+ /* Expected winner(s), maybe NULL */
struct result *expected;
size_t expected_len;
- uint16_t id;
- struct GNUNET_CRYPTO_EccDlogContext *edc;
+
+ /*
+ * These are the results from the replay via the external program.
+ */
+ struct result *results;
+ size_t results_len;
};
/**
@@ -71,16 +100,25 @@ struct transcript
*/
static enum GNUNET_GenericReturnValue
json_error (json_t **output,
- char *error)
+ char *error, ...)
{
+ va_list ap;
+ int n = 0;
+ char buf[4096];
GNUNET_assert (error);
- *output = json_pack ("{s:s}", "error", error);
- GNUNET_assert (*output);
+ va_start (ap, error);
+ n = vsprintf (buf, error, ap);
+ va_end (ap);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
LOG_PREFIX "got error: %s\n",
- error);
+ n < 0 ? error: buf);
+
+ *output = json_pack ("{s:s}",
+ "error",
+ n < 0 ? error : buf);
+ GNUNET_assert (*output);
return GNUNET_SYSERR;
};
@@ -129,118 +167,153 @@ json_result (json_t **output,
* @brief Parses a given json as transcript.
*
* @param[in] jtr JSON input
- * @param[out] transcript Parsed transcript data
- * @param[out] jresult JSON output, both, for results or errors
+ * @param[out] tr Parsed transcript data
+ * @param[out] jerror JSON output for errors
* @return GNUNET_OK on succes
*
* TODO:
- * - fix leakages
* - parse and verify signatures
*/
static enum GNUNET_GenericReturnValue
parse_transcript (const json_t *jtr,
struct transcript *tr,
- json_t **output)
+ json_t **jerror)
{
+ json_t *auc;
+
// TODO: struct GNUNET_CRYPTO_EddsaSignature sig;
GNUNET_assert (jtr);
GNUNET_assert (tr);
+ // Parse auction
{
- json_t *auc;
char *perr;
unsigned int eline;
struct GNUNET_JSON_Specification au_spec[] = {
GNUNET_JSON_spec_bool ("public", &tr->public),
GNUNET_JSON_spec_uint16 ("type", &tr->m),
+ GNUNET_JSON_spec_fixed_auto ("pubkey", &tr->seller_pub),
+ GNUNET_JSON_spec_timestamp ("time_start", &tr->time_start),
+ GNUNET_JSON_spec_relative_time ("time_round", &tr->time_round),
+ GNUNET_JSON_spec_string ("payto", &tr->payto),
GNUNET_JSON_spec_end ()
};
auc = json_object_get (jtr, "auction");
if (NULL == auc)
- return json_error (output, "no auction found in transcript");
+ return json_error (jerror,
+ "no auction found in transcript");
if (GNUNET_OK !=
GNUNET_JSON_parse (auc,
au_spec,
(const char **) &perr,
&eline))
- return json_error (output, perr);
+ return json_error (jerror,
+ perr);
// Prices...
{
- json_t *prices = json_object_get (auc, "prices");
size_t idx;
json_t *val;
+ json_t *prices;
-
+ prices = json_object_get (auc, "prices");
if (! json_is_array (prices))
- // TODO: fix leak!?
- return json_error (output, "no prices found");
+ return json_error (jerror,
+ "no prices found");
tr->k = json_array_size (prices);
- tr->prices = GNUNET_new_array (tr->k, char *);
+ tr->prices = GNUNET_new_array (tr->k, struct TALER_Amount);
json_array_foreach (prices, idx, val)
{
- if (! json_is_string (val))
- // TODO: fix leak!_
- return json_error (output, "prices not strings");
-
- tr->prices[idx] = (char *) json_string_value (val);
-
- // TODO: parse prices
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount (NULL,
+ currency,
+ &(tr->prices[idx])),
+ GNUNET_JSON_spec_end (),
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ NULL,
+ NULL))
+ return json_error (jerror,
+ "price no. %ld couldn't be parsed",
+ idx + 1);
}
}
}
// Bidders
{
+ size_t idx;
+ json_t *val;
json_t *bidders;
bidders = json_object_get (jtr, "bidders");
if (! bidders || ! json_is_array (bidders))
- // TODO: fix leak!_
- return json_error (output, "bidders not found");
+ return json_error (jerror,
+ "no bidders found");
- // TODO: parse bidders as pub keys;
tr->n = json_array_size (bidders);
+
+ tr->bidder_pub = GNUNET_new_array (tr->n, struct
+ GNUNET_CRYPTO_EddsaPublicKey);
+ json_array_foreach (bidders, idx, val)
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto (NULL,
+ &(tr->bidder_pub[idx])),
+ GNUNET_JSON_spec_end (),
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ NULL,
+ NULL))
+ return json_error (jerror,
+ "bidder no %ld public key couldn't be parsed",
+ idx + 1);
+ }
}
+ // TODO: parse and verify signatures from bidders of the auction
+
// Messages
{
- json_t *messages;
size_t nm;
+ json_t *messages = json_object_get (jtr, "transcript");
- messages = json_object_get (jtr, "transcript");
if (! json_is_array (messages))
- // TODO: fix leak!
- return json_error (output, "no messages found");
+ return json_error (jerror,
+ "no messages found");
nm = json_array_size (messages);
if (nm != (4 * tr->n))
- // TODO: fix leak!
- return json_error (output, "not the right no. of messages found");
+ return json_error (jerror,
+ "not the right no. of messages found");
+
+ /* TODO: parse and evaluate signatures */
}
// Winners
{
- json_t *winners;
size_t idx;
json_t *val;
-
- winners = json_object_get (jtr, "winners");
+ json_t *winners = json_object_get (jtr, "winners");
if (! json_is_array (winners))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
LOG_PREFIX "winners not provided, continuing without\n");
- // TODO: fix leakage
- goto CONT;
+ goto DONE;
}
tr->expected_len = json_array_size (winners);
@@ -248,8 +321,6 @@ parse_transcript (const json_t *jtr,
struct result);
json_array_foreach (winners, idx, val) {
- char *error;
-
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint16 ("bidder",
&(tr->expected[idx].bidder)),
@@ -263,16 +334,21 @@ parse_transcript (const json_t *jtr,
if (GNUNET_OK !=
GNUNET_JSON_parse (val,
spec,
- (const char**) &error,
+ NULL,
NULL))
- // TODO: fix leak!
- return json_error (output, "couldn't parse winners");
+ return json_error (jerror,
+ "couldn't parse winner no. %ld",
+ idx + 1);
}
-
-CONT:
- // TODO: fix leakages
}
- *output = NULL;
+
+ // TODO: parse and evalue sig of seller
+
+// TODO: check for max values
+
+DONE:
+
+ *jerror = NULL;
return GNUNET_OK;
}
@@ -285,7 +361,7 @@ CONT:
* @param[out] result The JSON result from the program
* @return GNUNET_OK on success
*
- * TODO: Make this asynchronous (giving out a replay-ID to poll from)?
+ * TODO: Make this resumable
*/
static enum GNUNET_GenericReturnValue
replay_transcript (const json_t*root,
@@ -338,6 +414,9 @@ replay_transcript (const json_t*root,
{
ssize_t sz;
char buf[MAX_RESULT_SIZE];
+ json_error_t error;
+ json_t *res;
+
fd = GNUNET_DISK_pipe_handle (po, GNUNET_DISK_PIPE_END_READ);
sz = GNUNET_DISK_file_read (fd,
@@ -347,21 +426,62 @@ replay_transcript (const json_t*root,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
LOG_PREFIX "couldn't read data from replay_program\n");
+ return json_error (result, "internal error");
}
- else
+
+ buf[sz] = 0;
+ res = json_loads (buf,
+ JSON_DECODE_ANY,
+ &error);
+
+ if (! res)
{
- json_error_t error;
- json_t *res;
- res = json_loads (buf,
- JSON_DECODE_ANY,
- &error);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ LOG_PREFIX
+ "couldn't parse response from replay_program: %s (for '%s')\n",
+ error.text,
+ buf);
+ return json_error (result, error.text);
+ }
- if (! res)
- return json_error (result, error.text);
+ // Handle error case first
+ {
+ json_t *err = json_object_get (res,
+ "error");
+ if (NULL != err)
+ {
+ *result = json_copy (res);
+ json_decref (res);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ // Parse the result
+ {
+ json_t *winners = json_object_get (res,
+ "winners");
+ if ((NULL == winners) ||
+ (! json_is_array (winners)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX
+ "replay program didn't return a known result type, instead: '%s'\n",
+ json_dumps (res, JSON_INDENT (2)));
+ return json_error (result, "internal error");
+ }
+
+ {
+ // TODO: check each winner with tr->expected, if applicable
+ json_object_set (res, "exchange_sig", json_string (
+ "sig(priv_E, winners)"));
+
+ }
+ // TODO: return own result object.
*result = json_copy (res);
json_decref (res);
}
+
}
if (GNUNET_OK != GNUNET_OS_process_wait (proc))
@@ -375,7 +495,6 @@ replay_transcript (const json_t*root,
}
- // TODO: parse result
return GNUNET_OK;
}
@@ -389,6 +508,7 @@ static void
auction_disable (
struct TALER_Extension *ext)
{
+ /* TODO: cleanup configuration */
ext->enabled = false;
}
@@ -418,7 +538,7 @@ static json_t *
auction_config_to_json (
const struct TALER_Extension *ext)
{
- /* This extension has no configuration */
+ /* TODO: add configuration */
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_bool ("critical", ext->critical),
GNUNET_JSON_pack_string ("version", ext->version));
@@ -436,7 +556,7 @@ auction_load_json_config (
struct TALER_Extension *ext,
json_t *jconfig)
{
- /* This extension has no configuration */
+ /* TODO: add configuration */
ext->enabled = true;
return GNUNET_OK;
}
@@ -465,6 +585,8 @@ auction_http_get_handler (
/**
* @brief implements the TALER_Extension.http_post_handler
+ *
+ * TODO: make this non-blocking
*/
static MHD_RESULT
auction_http_post_handler (
@@ -505,7 +627,7 @@ struct TALER_Extension TE_auction_brandt = {
.critical = false,
.version = "0",
.enabled = false, /* disabled per default */
- .has_config = false, /* This extension has no configuration */
+ .has_config = true,
.config = NULL,
.config_json = NULL,
.disable = &auction_disable,
@@ -537,6 +659,12 @@ libtaler_extension_auction_brandt_init (void *arg)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = arg;
+
+ if (GNUNET_OK !=
+ TALER_config_get_currency (cfg,
+ &currency))
+ return NULL;
+
if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_string (cfg,
TALER_EXTENSION_SECTION_PREFIX
@@ -549,11 +677,37 @@ libtaler_extension_auction_brandt_init (void *arg)
"REPLAY_PROGRAM");
return NULL;
}
- /* TODO: check if replay_program is actually executable */
+
+ /* check if replay_program is actually an executable */
+ {
+ struct stat sb;
+
+ if (0 != stat (replay_program, &sb))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "replay_program '%s' not found\n",
+ replay_program);
+ return NULL;
+ }
+
+ if ( (sb.st_mode & S_IFDIR) ||
+ ! (sb.st_mode & S_IXUSR))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ LOG_PREFIX "replay_program '%s' is not an executable\n",
+ replay_program);
+ return NULL;
+ }
+
+ }
+
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
LOG_PREFIX "loading... using replay_program '%s'\n",
replay_program);
+ /* TODO: read other config parameters and generate configuration */
+
+
return &TE_auction_brandt;
}