/*
This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
#define LOG(kind,...) GNUNET_log_from (kind, "gnunet-scalarproduct",__VA_ARGS__)
-struct ScalarProductCallbackClosure
-{
- /**
- * the session key identifying this computation
- */
- struct GNUNET_HashCode key;
- /**
- * PeerID we want to compute a scalar product with
- */
- struct GNUNET_PeerIdentity peer;
-};
+/**
+ * the session key identifying this computation
+ */
+static struct GNUNET_HashCode session_key;
+
+/**
+ * PeerID we want to compute a scalar product with
+ */
+static struct GNUNET_PeerIdentity peer_id;
/**
* Option -p: destination peer identity for checking message-ids with
*/
-static char *input_peer_id = NULL;
+static char *input_peer_id;
/**
* Option -p: destination peer identity for checking message-ids with
*/
-static char *input_key = NULL;
+static char *input_session_key;
/**
* Option -e: vector to calculate a scalarproduct with
*/
-static char *input_elements = NULL;
+static char *input_elements;
/**
- * Option -m: message-ids to calculate a scalarproduct with
+ * Global return value
*/
-static char *input_mask = NULL;
+static int ret = -1;
/**
- * Global return value
+ * our Scalarproduct Computation handle
*/
-static int ret;
+static struct GNUNET_SCALARPRODUCT_ComputationHandle *computation;
/**
* Callback called if we are initiating a new computation session
- *
+ *
* @param cls unused
- * @param status if our job was successfully processed
+ * @param status if our job was successfully processed
*/
static void
responder_callback (void *cls,
enum GNUNET_SCALARPRODUCT_ResponseStatus status)
{
- struct ScalarProductCallbackClosure * closure = cls;
- ret = -1;
-
switch (status)
{
- case GNUNET_SCALARPRODUCT_Status_Success:
+ case GNUNET_SCALARPRODUCT_STATUS_SUCCESS:
ret = 0;
- LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s (&closure->key));
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Session %s concluded.\n",
+ GNUNET_h2s (&session_key));
break;
- case GNUNET_SCALARPRODUCT_Status_InvalidResponse:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", GNUNET_h2s (&closure->key));
+ case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s failed: invalid response\n",
+ GNUNET_h2s (&session_key));
break;
- case GNUNET_SCALARPRODUCT_Status_Failure:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", GNUNET_h2s (&closure->key));
- case GNUNET_SCALARPRODUCT_Status_ServiceDisconnected:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service disconnect!!\n", GNUNET_h2s (&closure->key));
+ case GNUNET_SCALARPRODUCT_STATUS_FAILURE:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s failed: service failure\n",
+ GNUNET_h2s (&session_key));
+ break;
+ case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s failed: service disconnect!\n",
+ GNUNET_h2s (&session_key));
break;
default:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", GNUNET_h2s (&closure->key), status);
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s failed: return code %d\n",
+ GNUNET_h2s (&session_key),
+ status);
}
-
- GNUNET_SCALARPRODUCT_disconnect ();
+ computation = NULL;
GNUNET_SCHEDULER_shutdown ();
}
/**
* Callback called if we are initiating a new computation session
- *
+ *
* @param cls unused
- * @param key unused
- * @param peer unused
- * @param status if our job was successfully processed
- * @param size size of the msg returned
- * @param msg the response we got.
- * @param type of the message received
+ * @param status if our job was successfully processed
+ * @param result the result in gnu/gcry MPI format
*/
static void
requester_callback (void *cls,
enum GNUNET_SCALARPRODUCT_ResponseStatus status,
gcry_mpi_t result)
{
- struct ScalarProductCallbackClosure * closure = cls;
- unsigned char * buf;
+ unsigned char *buf;
gcry_error_t rc;
- ret = -1;
switch (status)
{
- case GNUNET_SCALARPRODUCT_Status_Success:
-
+ case GNUNET_SCALARPRODUCT_STATUS_SUCCESS:
if (0 == (rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result)))
- printf("%s", buf);
+ {
+ ret = 0;
+ fprintf (stdout,
+ "%s\n",
+ buf);
+ fflush (stdout);
+ }
else
- LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_aprint", rc);
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
+ "gcry_mpi_aprint",
+ rc);
break;
- case GNUNET_SCALARPRODUCT_Status_InvalidResponse:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s with peer %s failed: invalid response received\n", GNUNET_h2s (&closure->key), GNUNET_i2s (&closure->peer));
+ case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s with peer %s failed: invalid response received\n",
+ GNUNET_h2s (&session_key),
+ GNUNET_i2s (&peer_id));
break;
- case GNUNET_SCALARPRODUCT_Status_Failure:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s with peer %s failed: API failure\n", GNUNET_h2s (&closure->key), GNUNET_i2s (&closure->peer));
- case GNUNET_SCALARPRODUCT_Status_ServiceDisconnected:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s with peer %s was disconnected from service.\n", GNUNET_h2s (&closure->key), GNUNET_i2s (&closure->peer));
+ case GNUNET_SCALARPRODUCT_STATUS_FAILURE:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s with peer %s failed: API failure\n",
+ GNUNET_h2s (&session_key),
+ GNUNET_i2s (&peer_id));
+ break;
+ case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s with peer %s was disconnected from service.\n",
+ GNUNET_h2s (&session_key),
+ GNUNET_i2s (&peer_id));
break;
default:
- LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s with peer %s failed: return code %d\n", GNUNET_h2s (&closure->key), GNUNET_i2s (&closure->peer), status);
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Session %s with peer %s failed: return code %d\n",
+ GNUNET_h2s (&session_key),
+ GNUNET_i2s (&peer_id),
+ status);
}
- GNUNET_SCALARPRODUCT_disconnect ();
+ computation = NULL;
GNUNET_SCHEDULER_shutdown ();
}
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != computation)
+ {
+ GNUNET_SCALARPRODUCT_cancel (computation);
+ ret = 1; /* aborted */
+ }
+}
+
+
/**
* Main function that will be run by the scheduler.
*
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- char * begin = input_elements;
- char * end;
- int32_t element;
- int i;
- ret = -1;
- int32_t * elements;
- unsigned char * mask;
- unsigned short mask_bytes;
- unsigned short element_count;
- struct ScalarProductCallbackClosure * closure;
+ char *begin = input_elements;
+ char *end;
+ unsigned int i;
+ struct GNUNET_SCALARPRODUCT_Element *elements;
+ uint32_t element_count = 0;
if (NULL == input_elements)
{
- FPRINTF (stderr, "%s", _ ("You must specify at least one message ID to check!\n"));
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("You must specify at least one message ID to check!\n"));
return;
}
-
- if (NULL == input_key)
+ if ( (NULL == input_session_key) ||
+ (0 == strlen (input_session_key)) )
{
- FPRINTF (stderr, "%s", _ ("This program needs a session identifier for comparing vectors.\n"));
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("This program needs a session identifier for comparing vectors.\n"));
return;
}
-
- if (1 > strnlen (input_key, sizeof (struct GNUNET_HashCode)))
+ GNUNET_CRYPTO_hash (input_session_key,
+ strlen (input_session_key),
+ &session_key);
+ if ( (NULL != input_peer_id) &&
+ (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (input_peer_id,
+ strlen (input_peer_id),
+ &peer_id.public_key)) )
{
- FPRINTF (stderr, _ ("Please give a session key for --input_key!\n"));
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Tried to set initiator mode, as peer ID was given. "
+ "However, `%s' is not a valid peer identifier.\n"),
+ input_peer_id);
return;
}
- closure = GNUNET_new(struct ScalarProductCallbackClosure);
- GNUNET_CRYPTO_hash (input_key, strlen (input_key), &closure->key);
-
- if (input_peer_id && GNUNET_OK != GNUNET_CRYPTO_hash_from_string (input_peer_id,
- (struct GNUNET_HashCode *) &closure->peer))
+ if ( ('\'' == *begin) &&
+ ('\'' == begin[strlen(begin)-1]) )
{
- FPRINTF (stderr, _ ("Tried to set initiator mode, as peer ID was given. "
- "However, `%s' is not a valid peer identifier.\n"),
- input_peer_id);
+ begin[strlen(begin)-1] = '\0';
+ if (strlen (begin) > 0)
+ begin++;
+ }
+ for (end = begin; 0 != *end; end++)
+ if (*end == ';')
+ element_count++;
+ if (0 == element_count)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Need elements to compute the scalarproduct, got none.\n"));
return;
}
- int exit_loop = 0;
- /* Read input_elements_peer1, and put in elements_peer1 array */
- do
- {
- unsigned int mcount = element_count;
- //ignore empty rows of ,,,,,,
- while (*begin == ',')
- begin++;
- // get the length of the current element and replace , with null
- for (end = begin; *end && *end != ','; end++);
+ elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
- if (*end == '\0')
- exit_loop = 1;
+ for (i = 0; i < element_count;i++)
+ {
+ struct GNUNET_SCALARPRODUCT_Element element;
+ char* separator = NULL;
- if (*end == ',')
- *end = '\0';
+ /* get the length of the current key,value; tupel */
+ for (end = begin; *end != ';'; end++)
+ if (*end == ',')
+ separator = end;
- if (1 != sscanf (begin, "%" SCNd32, &element))
+ /* final element */
+ if ( (NULL == separator) ||
+ (begin == separator) ||
+ (separator == end - 1) )
{
- FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Malformed input, could not parse `%s'\n"),
+ begin);
+ GNUNET_free (elements);
return;
}
-
- GNUNET_array_append (elements, mcount, element);
- element_count++;
-
- begin = ++end;
- }
- while (!exit_loop);
-
- GNUNET_assert (elements != NULL);
- GNUNET_assert (element_count > 1);
- mask_bytes = element_count / 8 + (element_count % 8 ? 1 : 0);
- mask = GNUNET_malloc ((element_count / 8) + 2);
-
- /* Read input_mask_peer1 and read in mask_peer1 array */
- if (NULL != input_mask)
- {
- begin = input_mask;
- unsigned short mask_count = 0;
- int exit_loop = 0;
-
- do
+ *separator = 0;
+ /* read the element's key */
+ GNUNET_CRYPTO_hash (begin,
+ strlen (begin),
+ &element.key);
+
+ /* read the element's value */
+ if (1 !=
+ sscanf (separator + 1,
+ "%" SCNd64 ";",
+ &element.value) )
{
- //ignore empty rows of ,,,,,,
- while (* begin == ',')
- begin++;
- // get the length of the current element and replace , with null
- // gnunet_ascii-armor uses base32, thus we can use , as separator!
- for (end = begin; *end && *end != ','; end++);
-
- if (*end == '\0')
- exit_loop = 1;
-
- if (*end == ',')
- *end = '\0';
-
- if (1 != sscanf (begin, "%" SCNd32, &element))
- {
- FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
- return;
- }
-
- GNUNET_assert (mask_count <= element_count);
-
- if (element)
- mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 8);
-
- mask_count++;
- begin = ++end;
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not convert `%s' to int64_t.\n"),
+ begin);
+ GNUNET_free (elements);
+ return;
}
- while (!exit_loop);
- // +1 to see if we would have more data, which would indicate malformed/superficial input
- GNUNET_assert (mask_count == element_count);
- }
- else if (input_peer_id)
- {
- for (i = 0; i <= mask_bytes; i++)
- mask[i] = UCHAR_MAX; // all 1's
+ element.value = GNUNET_htonll (element.value);
+ elements[i] = element;
+ begin = end + 1;
}
-
- if (input_peer_id && !GNUNET_SCALARPRODUCT_request (cfg,
- &closure->key,
- &closure->peer,
- elements, element_count,
- mask, mask_bytes,
- &requester_callback,
- (void *) &closure))
- return;
-
-
- if (!input_peer_id && !GNUNET_SCALARPRODUCT_response (cfg,
- &closure->key,
- elements, element_count,
- &responder_callback,
- (void *) &closure))
+ if ( ( (NULL != input_peer_id) &&
+ (NULL == (computation
+ = GNUNET_SCALARPRODUCT_start_computation (cfg,
+ &session_key,
+ &peer_id,
+ elements, element_count,
+ &requester_callback,
+ NULL))) ) ||
+ ( (NULL == input_peer_id) &&
+ (NULL == (computation
+ = GNUNET_SCALARPRODUCT_accept_computation (cfg,
+ &session_key,
+ elements, element_count,
+ &responder_callback,
+ NULL))) ) )
+ {
+ fprintf (stderr,
+ _("Failed to initiate computation, were all keys unique?\n"));
+ GNUNET_free (elements);
return;
-
+ }
+ GNUNET_free (elements);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task,
+ NULL);
ret = 0;
}
- /**
+/**
* The main function to the scalarproduct client.
*
* @param argc number of arguments from the command line
* @param argv command line arguments
* @return 0 ok, 1 on error
*/
- int
+int
main (int argc, char *const *argv)
{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'e', "elements", "\"val1,val2,...,valn\"",
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'e', "elements", "\"key1,val1;key2,val2;...,keyn,valn;\"",
gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
1, &GNUNET_GETOPT_set_string, &input_elements},
- {'m', "mask", "\"0,1,...,maskn\"",
- gettext_noop ("A comma separated mask to select which elements should actually be compared."),
- 1, &GNUNET_GETOPT_set_string, &input_mask},
{'p', "peer", "PEERID",
gettext_noop ("[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."),
1, &GNUNET_GETOPT_set_string, &input_peer_id},
{'k', "key", "TRANSACTION_ID",
gettext_noop ("Transaction ID shared with peer."),
- 1, &GNUNET_GETOPT_set_string, &input_key},
- GNUNET_GETOPT_OPTION_END
+ 1, &GNUNET_GETOPT_set_string, &input_session_key},
+ GNUNET_GETOPT_OPTION_END
};
- return (GNUNET_OK ==
- GNUNET_PROGRAM_run (argc,
- argv,
- "gnunet-scalarproduct",
- gettext_noop ("Calculate the Vectorproduct with a GNUnet peer."),
- options, &run, NULL)) ? ret : 1;
+ return (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc,
+ argv,
+ "gnunet-scalarproduct",
+ gettext_noop ("Calculate the Vectorproduct with a GNUnet peer."),
+ options, &run, NULL)) ? ret : 1;
}
+/* end of gnunet-scalarproduct.c */