diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/extensions/auction_brandt/extension_auction_brandt.c | 302 | 
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, +                                 ¤cy)) +    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;  } | 
