+/**
+ * How big is the BF we use for REGEX blocks?
+ */
+#define REGEX_BF_SIZE 8
+
+
+/**
+ * Create a new block group.
+ *
+ * @param ctx block context in which the block group is created
+ * @param type type of the block for which we are creating the group
+ * @param nonce random value used to seed the group creation
+ * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
+ * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
+ * @param va variable arguments specific to @a type
+ * @return block group handle, NULL if block groups are not supported
+ * by this @a type of block (this is not an error)
+ */
+static struct GNUNET_BLOCK_Group *
+block_plugin_regex_create_group (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ uint32_t nonce,
+ const void *raw_data,
+ size_t raw_data_size,
+ va_list va)
+{
+ unsigned int bf_size;
+ const char *guard;
+
+ guard = va_arg (va, const char *);
+ if (0 == strcmp (guard,
+ "seen-set-size"))
+ bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned int),
+ BLOOMFILTER_K);
+ else if (0 == strcmp (guard,
+ "filter-size"))
+ bf_size = va_arg (va, unsigned int);
+ else
+ {
+ GNUNET_break (0);
+ bf_size = REGEX_BF_SIZE;
+ }
+ GNUNET_break (NULL == va_arg (va, const char *));
+ return GNUNET_BLOCK_GROUP_bf_create (cls,
+ bf_size,
+ BLOOMFILTER_K,
+ type,
+ nonce,
+ raw_data,
+ raw_data_size);
+}
+
+
+/**
+ * Function called to validate a reply or a request of type
+ * #GNUNET_BLOCK_TYPE_REGEX.
+ * For request evaluation, pass "NULL" for the reply_block.
+ * Note that it is assumed that the reply has already been
+ * matched to the key (and signatures checked) as it would
+ * be done with the #GNUNET_BLOCK_get_key() function.
+ *
+ * @param cls closure
+ * @param type block type
+ * @param bg block group to evaluate against
+ * @param eo control flags
+ * @param query original query (hash)
+ * @param xquery extrended query data (can be NULL, depending on type)
+ * @param xquery_size number of bytes in @a xquery
+ * @param reply_block response to validate
+ * @param reply_block_size number of bytes in @a reply_block
+ * @return characterization of result
+ */
+static enum GNUNET_BLOCK_EvaluationResult
+evaluate_block_regex (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
+ enum GNUNET_BLOCK_EvaluationOptions eo,
+ const struct GNUNET_HashCode *query,
+ const void *xquery,
+ size_t xquery_size,
+ const void *reply_block,
+ size_t reply_block_size)
+{
+ struct GNUNET_HashCode chash;
+
+ if (NULL == reply_block)
+ {
+ if (0 != xquery_size)
+ {
+ const char *s;
+
+ s = (const char *) xquery;
+ if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
+ {
+ GNUNET_break_op (0);
+ return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
+ }
+ }
+ return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
+ }
+ if (0 != xquery_size)
+ {
+ const char *s;
+
+ s = (const char *) xquery;
+ if ('\0' != s[xquery_size - 1]) /* must be valid 0-terminated string */
+ {
+ GNUNET_break_op (0);
+ return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
+ }
+ }
+ else if (NULL != query)
+ {
+ /* xquery is required for regex GETs, at least an empty string */
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "type %d, query %p, xquery %p\n",
+ type, query, xquery);
+ return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
+ }
+ switch (REGEX_BLOCK_check (reply_block,
+ reply_block_size,
+ query,
+ xquery))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break_op(0);
+ return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
+ case GNUNET_NO:
+ /* xquery missmatch, can happen */
+ return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
+ default:
+ break;
+ }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
+ return GNUNET_BLOCK_EVALUATION_OK_MORE;
+}
+
+
+/**
+ * Function called to validate a reply or a request of type
+ * #GNUNET_BLOCK_TYPE_REGEX_ACCEPT.
+ * For request evaluation, pass "NULL" for the reply_block.
+ * Note that it is assumed that the reply has already been
+ * matched to the key (and signatures checked) as it would
+ * be done with the #GNUNET_BLOCK_get_key() function.
+ *
+ * @param cls closure
+ * @param type block type
+ * @param bg block group to evaluate against
+ * @param eo control flags
+ * @param query original query (hash)
+ * @param xquery extrended query data (can be NULL, depending on type)
+ * @param xquery_size number of bytes in @a xquery
+ * @param reply_block response to validate
+ * @param reply_block_size number of bytes in @a reply_block
+ * @return characterization of result
+ */
+static enum GNUNET_BLOCK_EvaluationResult
+evaluate_block_regex_accept (void *cls,
+ enum GNUNET_BLOCK_Type type,
+ struct GNUNET_BLOCK_Group *bg,
+ enum GNUNET_BLOCK_EvaluationOptions eo,
+ const struct GNUNET_HashCode *query,
+ const void *xquery,
+ size_t xquery_size, const void *reply_block,
+ size_t reply_block_size)
+{
+ const struct RegexAcceptBlock *rba;
+ struct GNUNET_HashCode chash;
+
+ if (0 != xquery_size)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
+ }
+ if (NULL == reply_block)
+ return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
+ if (sizeof (struct RegexAcceptBlock) != reply_block_size)
+ {
+ GNUNET_break_op(0);
+ return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
+ }
+ rba = reply_block;
+ if (ntohl (rba->purpose.size) !=
+ sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_HashCode))
+ {
+ GNUNET_break_op(0);
+ return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
+ }
+ if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (rba->expiration_time)).rel_value_us)
+ {
+ /* technically invalid, but can happen without an error, so
+ we're nice by reporting it as a 'duplicate' */
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT,
+ &rba->purpose,
+ &rba->signature,
+ &rba->peer.public_key))
+ {
+ GNUNET_break_op(0);
+ return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
+ }
+ GNUNET_CRYPTO_hash (reply_block,
+ reply_block_size,
+ &chash);
+ if (GNUNET_YES ==
+ GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
+ &chash))
+ return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
+ return GNUNET_BLOCK_EVALUATION_OK_MORE;
+}
+
+