X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fscalarproduct%2Fgnunet-service-scalarproduct.c;h=fbdb58a2331a2d02c888a0cb76da3955f24c01e5;hb=d0a9f269aa6575253b1c284d594a467e6fdeb7c7;hp=3494703333e04d3ea46744dea3f7eee2261a534c;hpb=a1d37f58a2f5dad49539fb271c5c027907fc34eb;p=oweals%2Fgnunet.git diff --git a/src/scalarproduct/gnunet-service-scalarproduct.c b/src/scalarproduct/gnunet-service-scalarproduct.c index 349470333..fbdb58a23 100644 --- a/src/scalarproduct/gnunet-service-scalarproduct.c +++ b/src/scalarproduct/gnunet-service-scalarproduct.c @@ -44,14 +44,15 @@ */ enum SessionState { - CLIENT_REQUEST_RECEIVED, - WAITING_FOR_BOBS_CONNECT, - CLIENT_RESPONSE_RECEIVED, - WAITING_FOR_SERVICE_REQUEST, - WAITING_FOR_SERVICE_RESPONSE, - SERVICE_REQUEST_RECEIVED, - SERVICE_RESPONSE_RECEIVED, - FINALIZED + CLIENT_REQUEST_RECEIVED, + WAITING_FOR_BOBS_CONNECT, + CLIENT_RESPONSE_RECEIVED, + WAITING_FOR_SERVICE_REQUEST, + WAITING_FOR_MULTIPART_TRANSMISSION, + WAITING_FOR_SERVICE_RESPONSE, + SERVICE_REQUEST_RECEIVED, + SERVICE_RESPONSE_RECEIVED, + FINALIZED }; /** @@ -59,119 +60,159 @@ enum SessionState */ enum PeerRole { - ALICE, - BOB + ALICE, + BOB }; - /** * A scalarproduct session which tracks: - * + * * a request form the client to our final response. * or * a request from a service to us(service). */ struct ServiceSession { - /** - * the role this peer has - */ - enum PeerRole role; - - /** - * session information is kept in a DLL - */ - struct ServiceSession *next; - - /** - * session information is kept in a DLL - */ - struct ServiceSession *prev; - - /** - * (hopefully) unique transaction ID - */ - struct GNUNET_HashCode key; - - /** - * state of the session - */ - enum SessionState state; - - /** - * Alice or Bob's peerID - */ - struct GNUNET_PeerIdentity peer; - - /** - * the client this request is related to - */ - struct GNUNET_SERVER_Client * client; - - /** - * The message to send - */ - struct GNUNET_MessageHeader * msg; - - /** - * how many elements we were supplied with from the client - */ - uint32_t element_count; - - /** - * how many elements actually are used after applying the mask - */ - uint32_t used_element_count; - - /** - * how many bytes the mask is long. - * just for convenience so we don't have to re-re-re calculate it each time - */ - uint32_t mask_length; - - /** - * all the vector elements we received - */ - int32_t * vector; - - /** - * mask of which elements to check - */ - unsigned char * mask; - - /** - * Public key of the remote service, only used by bob - */ - gcry_sexp_t remote_pubkey; - - /** - * E(ai)(Bob) or ai(Alice) after applying the mask - */ - gcry_mpi_t * a; - - /** - * The computed scalar - */ - gcry_mpi_t product; - - /** - * My transmit handle for the current message to a alice/bob - */ - struct GNUNET_MESH_TransmitHandle * service_transmit_handle; - - /** - * My transmit handle for the current message to the client - */ - struct GNUNET_SERVER_TransmitHandle * client_transmit_handle; - - /** - * tunnel-handle associated with our mesh handle - */ - struct GNUNET_MESH_Tunnel * tunnel; - - GNUNET_SCHEDULER_TaskIdentifier client_notification_task; - - GNUNET_SCHEDULER_TaskIdentifier service_request_task; + /** + * the role this peer has + */ + enum PeerRole role; + + /** + * session information is kept in a DLL + */ + struct ServiceSession *next; + + /** + * session information is kept in a DLL + */ + struct ServiceSession *prev; + + /** + * (hopefully) unique transaction ID + */ + struct GNUNET_HashCode key; + + /** + * state of the session + */ + enum SessionState state; + + /** + * Alice or Bob's peerID + */ + struct GNUNET_PeerIdentity peer; + + /** + * the client this request is related to + */ + struct GNUNET_SERVER_Client * client; + + /** + * The message to send + */ + struct GNUNET_MessageHeader * msg; + + /** + * how many elements we were supplied with from the client + */ + uint32_t total; + + /** + * how many elements actually are used after applying the mask + */ + uint32_t used; + + /** + * already transferred elements (sent/received) for multipart messages, less or equal than used_element_count for + */ + uint32_t transferred; + + /** + * index of the last transferred element for multipart messages + */ + uint32_t last_processed; + + /** + * how many bytes the mask is long. + * just for convenience so we don't have to re-re-re calculate it each time + */ + uint32_t mask_length; + + /** + * all the vector elements we received + */ + int32_t * vector; + + /** + * mask of which elements to check + */ + unsigned char * mask; + + /** + * Public key of the remote service, only used by bob + */ + gcry_sexp_t remote_pubkey; + + /** + * E(ai)(Bob) or ai(Alice) after applying the mask + */ + gcry_mpi_t * a; + + /** + * Bob's permutation p of R + */ + gcry_mpi_t * r; + + /** + * Bob's permutation q of R + */ + gcry_mpi_t * r_prime; + + /** + * Bob's s + */ + gcry_mpi_t s; + + /** + * Bob's s' + */ + gcry_mpi_t s_prime; + + /** + * Bobs matching response session from the client + */ + struct ServiceSession * response; + + /** + * The computed scalar + */ + gcry_mpi_t product; + + /** + * My transmit handle for the current message to a alice/bob + */ + struct GNUNET_MESH_TransmitHandle * service_transmit_handle; + + /** + * My transmit handle for the current message to the client + */ + struct GNUNET_SERVER_TransmitHandle * client_transmit_handle; + + /** + * tunnel-handle associated with our mesh handle + */ + struct GNUNET_MESH_Tunnel * tunnel; + + /** + * Handle to a task that sends a msg to the our client + */ + GNUNET_SCHEDULER_TaskIdentifier client_notification_task; + + /** + * Handle to a task that sends a msg to the our peer + */ + GNUNET_SCHEDULER_TaskIdentifier service_request_task; }; /////////////////////////////////////////////////////////////////////////////// @@ -230,27 +271,27 @@ static gcry_mpi_t my_lambda; static gcry_mpi_t my_offset; /** - * Head of our double linked list for client-requests sent to us. + * Head of our double linked list for client-requests sent to us. * for all of these elements we calculate a scalar product with a remote peer * split between service->service and client->service for simplicity */ static struct ServiceSession * from_client_head; /** - * Tail of our double linked list for client-requests sent to us. + * Tail of our double linked list for client-requests sent to us. * for all of these elements we calculate a scalar product with a remote peer * split between service->service and client->service for simplicity */ static struct ServiceSession * from_client_tail; /** - * Head of our double linked list for service-requests sent to us. + * Head of our double linked list for service-requests sent to us. * for all of these elements we help the requesting service in calculating a scalar product * split between service->service and client->service for simplicity */ static struct ServiceSession * from_service_head; /** - * Tail of our double linked list for service-requests sent to us. + * Tail of our double linked list for service-requests sent to us. * for all of these elements we help the requesting service in calculating a scalar product * split between service->service and client->service for simplicity */ @@ -271,7 +312,7 @@ static int do_shutdown; static void generate_keyset () { - gcry_sexp_t gen_parms; + gcry_sexp_t gen_params; gcry_sexp_t key; gcry_sexp_t tmp_sexp; gcry_mpi_t p; @@ -283,14 +324,14 @@ generate_keyset () size_t erroff = 0; // we can still use the RSA keygen for generating p,q,n, but using e is pointless. - GNUNET_assert (0 == gcry_sexp_build (&gen_parms, &erroff, + GNUNET_assert (0 == gcry_sexp_build (&gen_params, &erroff, "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))", KEYBITS)); - GNUNET_assert (0 == gcry_pk_genkey (&key, gen_parms)); - gcry_sexp_release (gen_parms); + GNUNET_assert (0 == gcry_pk_genkey (&key, gen_params)); + gcry_sexp_release (gen_params); - // get n and d of our publickey as MPI + // get n and d of our publickey as MPI tmp_sexp = gcry_sexp_find_token (key, "n", 0); GNUNET_assert (tmp_sexp); my_n = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG); @@ -323,28 +364,26 @@ generate_keyset () // generate a g gcry_mpi_mul (my_nsquare, my_n, my_n); - do - { - // find a matching g - do - { - gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM); - // g must be smaller than n^2 - if (0 >= gcry_mpi_cmp (my_g, my_nsquare)) - continue; - - // g must have gcd == 1 with n^2 - gcry_mpi_gcd (gcd, my_g, my_nsquare); - } - while (gcry_mpi_cmp_ui (gcd, 1)); - - // is this a valid g? - // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1 - gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare); - gcry_mpi_sub_ui (tmp1, tmp1, 1); - gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0); - gcry_mpi_gcd (gcd, tmp1, my_n); + do { + // find a matching g + do { + gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM); + // g must be smaller than n^2 + if (0 >= gcry_mpi_cmp (my_g, my_nsquare)) + continue; + + // g must have gcd == 1 with n^2 + gcry_mpi_gcd (gcd, my_g, my_nsquare); } + while (gcry_mpi_cmp_ui (gcd, 1)); + + // is this a valid g? + // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1 + gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare); + gcry_mpi_sub_ui (tmp1, tmp1, 1); + gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0); + gcry_mpi_gcd (gcd, tmp1, my_n); + } while (gcry_mpi_cmp_ui (gcd, 1)); // calculate our mu based on g and n. @@ -371,17 +410,16 @@ generate_keyset () my_pubkey_external_length); gcry_sexp_release (key); - + // offset has to be sufficiently small to allow computation of: - // m1+m2 mod n == (S + a) + (S + b) mod n, + // m1+m2 mod n == (S + a) + (S + b) mod n, // if we have more complex operations, this factor needs to be lowered - my_offset = gcry_mpi_new(KEYBITS/3); - gcry_mpi_set_bit(my_offset, KEYBITS/3); + my_offset = gcry_mpi_new (KEYBITS / 3); + gcry_mpi_set_bit (my_offset, KEYBITS / 3); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Generated key set with key length %d bits.\n"), KEYBITS); } - /** * If target != size, move target bytes to the * end of the size-sized buffer and zero out the @@ -394,17 +432,15 @@ generate_keyset () static void adjust (unsigned char *buf, size_t size, size_t target) { - if (size < target) - { - memmove (&buf[target - size], buf, size); - memset (buf, 0, target - size); - } + if (size < target) { + memmove (&buf[target - size], buf, size); + memset (buf, 0, target - size); + } } - /** * encrypts an element using the paillier crypto system - * + * * @param c ciphertext (output) * @param m plaintext * @param g the public base @@ -418,11 +454,10 @@ encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t n, gcry_mp GNUNET_assert (tmp = gcry_mpi_new (0)); - while (0 >= gcry_mpi_cmp_ui (tmp, 1)) - { - gcry_mpi_randomize (tmp, KEYBITS / 3, GCRY_WEAK_RANDOM); - // r must be 1 < r < n - } + while (0 >= gcry_mpi_cmp_ui (tmp, 1)) { + gcry_mpi_randomize (tmp, KEYBITS / 3, GCRY_WEAK_RANDOM); + // r must be 1 < r < n + } gcry_mpi_powm (c, g, m, n_square); gcry_mpi_powm (tmp, tmp, n, n_square); @@ -433,7 +468,7 @@ encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t n, gcry_mp /** * decrypts an element using the paillier crypto system - * + * * @param m plaintext (output) * @param c the ciphertext * @param mu the modifier to correct encryption @@ -450,10 +485,9 @@ decrypt_element (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, g gcry_mpi_mulm (m, m, mu, n); } - /** * computes the square sum over a vector of a given length. - * + * * @param vector the vector to encrypt * @param length the length of the vector * @return an MPI value containing the calculated sum, never NULL @@ -469,22 +503,29 @@ compute_square_sum (gcry_mpi_t * vector, uint32_t length) GNUNET_assert (elem = gcry_mpi_new (0)); // calculare E(sum (ai ^ 2), publickey) - for (i = 0; i < length; i++) - { - gcry_mpi_mul (elem, vector[i], vector[i]); - gcry_mpi_add (sum, sum, elem); - } + for (i = 0; i < length; i++) { + gcry_mpi_mul (elem, vector[i], vector[i]); + gcry_mpi_add (sum, sum, elem); + } gcry_mpi_release (elem); return sum; } +static void +prepare_service_request_multipart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); +static void +prepare_service_response_multipart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + /** * Primitive callback for copying over a message, as they * usually are too complex to be handled in the callback itself. * clears a session-callback, if a session was handed over and the transmit handle was stored - * + * * @param cls the message object * @param size the size of the buffer we got * @param buf the buffer to copy the message to @@ -494,38 +535,56 @@ static size_t do_send_message (void *cls, size_t size, void *buf) { struct ServiceSession * session = cls; - size_t written = 0; + uint16_t type; GNUNET_assert (buf); - if (ntohs (session->msg->size) == size) - { - memcpy (buf, session->msg, size); - written = size; - } - - switch (ntohs(session->msg->type)){ - case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT: - session->state = FINALIZED; - session->client_transmit_handle = NULL; - break; - default: - session->service_transmit_handle = NULL; + if (ntohs (session->msg->size) != size) + { + GNUNET_break (0); + return 0; } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sent a message of type %hu.\n", - ntohs (session->msg->type)); - GNUNET_free(session->msg); - session->msg = NULL; - return written; -} + type = ntohs (session->msg->type); + memcpy (buf, session->msg, size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sent a message of type %hu.\n", + type); + GNUNET_free (session->msg); + session->msg = NULL; + + switch (type) + { + case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT: + session->state = FINALIZED; + session->client_transmit_handle = NULL; + break; + case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB: + case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB_MULTIPART: + //else + session->service_transmit_handle = NULL; + // reset flags for sending + if ((session->state != WAITING_FOR_MULTIPART_TRANSMISSION) && (session->used != session->transferred)) + prepare_service_request_multipart (session, NULL); + //TODO we have sent a message and now need to trigger trigger the next multipart message sending + break; + case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE: + case GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE_MULTIPART: + //else + session->service_transmit_handle = NULL; + if ((session->state != WAITING_FOR_MULTIPART_TRANSMISSION) && (session->used != session->transferred)) + prepare_service_response_multipart (session, NULL); + break; + default: + session->service_transmit_handle = NULL; + } + return size; +} /** * initializes a new vector with fresh MPI values (=0) of a given length - * + * * @param length of the vector to create * @return the initialized vector, never NULL */ @@ -540,10 +599,9 @@ initialize_mpi_vector (uint32_t length) return output; } - /** * permutes an MPI vector according to the given permutation vector - * + * * @param vector the vector to permuted * @param perm the permutation to use * @param length the length of the vectors @@ -562,17 +620,16 @@ permute_vector (gcry_mpi_t * vector, // backup old layout memcpy (tmp, vector, length * sizeof (gcry_mpi_t)); - // permute vector according to given + // permute vector according to given for (i = 0; i < length; i++) vector[i] = tmp[perm[i]]; return vector; } - /** - * Populate a vector with random integer values and convert them to - * + * Populate a vector with random integer values and convert them to + * * @param length the length of the vector we must generate * @return an array of MPI values with random values */ @@ -584,30 +641,28 @@ generate_random_vector (uint32_t length) uint32_t i; random_vector = initialize_mpi_vector (length); - for (i = 0; i < length; i++) - { - value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); - - // long to gcry_mpi_t - if (value < 0) - gcry_mpi_sub_ui (random_vector[i], - random_vector[i], - -value); - else - random_vector[i] = gcry_mpi_set_ui (random_vector[i], value); - } + for (i = 0; i < length; i++) { + value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + + // long to gcry_mpi_t + if (value < 0) + gcry_mpi_sub_ui (random_vector[i], + random_vector[i], + -value); + else + random_vector[i] = gcry_mpi_set_ui (random_vector[i], value); + } return random_vector; } - /** - * Finds a not terminated client/service session in the + * Finds a not terminated client/service session in the * given DLL based on session key, element count and state. - * + * * @param tail - the tail of the DLL * @param my - the session to compare it to - * @return a pointer to a matching session, + * @return a pointer to a matching session, * else NULL */ static struct ServiceSession * @@ -619,36 +674,31 @@ find_matching_session (struct ServiceSession * tail, { struct ServiceSession * curr; - for (curr = tail; NULL != curr; curr = curr->prev) - { - // if the key matches, and the element_count is same - if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode))) - && (curr->element_count == element_count)) - { - // if incoming state is NULL OR is same as state of the queued request - if ((NULL == state) || (curr->state == *state)) - { - // if peerid is NULL OR same as the peer Id in the queued request - if ((NULL == peerid) - || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity)))) - // matches and is not an already terminated session - return curr; - } - } + for (curr = tail; NULL != curr; curr = curr->prev) { + // if the key matches, and the element_count is same + if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode))) + && (curr->total == element_count)) { + // if incoming state is NULL OR is same as state of the queued request + if ((NULL == state) || (curr->state == *state)) { + // if peerid is NULL OR same as the peer Id in the queued request + if ((NULL == peerid) + || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity)))) + // matches and is not an already terminated session + return curr; + } } + } return NULL; } - static void free_session (struct ServiceSession * session) { unsigned int i; - if (session->a) - { - for (i = 0; i < session->used_element_count; i++) + if (session->a) { + for (i = 0; i < session->used; i++) gcry_mpi_release (session->a[i]); GNUNET_free (session->a); @@ -667,9 +717,9 @@ free_session (struct ServiceSession * session) /////////////////////////////////////////////////////////////////////////////// /** - * A client disconnected. - * - * Remove the associated session(s), release datastructures + * A client disconnected. + * + * Remove the associated session(s), release datastructures * and cancel pending outgoing transmissions to the client. * if the session has not yet completed, we also cancel Alice's request to Bob. * @@ -681,47 +731,44 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { struct ServiceSession *session; - + + if (client == NULL) + return; session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession); if (NULL == session) return; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ ("Client (%p) disconnected from us.\n"), client); + _ ("Client (%p) disconnected from us.\n"), client); GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session); - - if (!(session->role == BOB && session->state == FINALIZED)) - { - //we MUST terminate any client message underway - if (session->service_transmit_handle && session->tunnel) - GNUNET_MESH_notify_transmit_ready_cancel (session->service_transmit_handle); - if (session->tunnel && session->state == WAITING_FOR_SERVICE_RESPONSE) - GNUNET_MESH_tunnel_destroy (session->tunnel); - } - if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) - { - GNUNET_SCHEDULER_cancel (session->client_notification_task); - session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task) - { - GNUNET_SCHEDULER_cancel (session->service_request_task); - session->service_request_task = GNUNET_SCHEDULER_NO_TASK; - } - if (NULL != session->client_transmit_handle) - { - GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle); - session->client_transmit_handle = NULL; - } + + if (!(session->role == BOB && session->state == FINALIZED)) { + //we MUST terminate any client message underway + if (session->service_transmit_handle && session->tunnel) + GNUNET_MESH_notify_transmit_ready_cancel (session->service_transmit_handle); + if (session->tunnel && session->state == WAITING_FOR_SERVICE_RESPONSE) + GNUNET_MESH_tunnel_destroy (session->tunnel); + } + if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) { + GNUNET_SCHEDULER_cancel (session->client_notification_task); + session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task) { + GNUNET_SCHEDULER_cancel (session->service_request_task); + session->service_request_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != session->client_transmit_handle) { + GNUNET_SERVER_notify_transmit_ready_cancel (session->client_transmit_handle); + session->client_transmit_handle = NULL; + } free_session (session); } - /** * Notify the client that the session has succeeded or failed completely. - * This message gets sent to + * This message gets sent to * * alice's client if bob disconnected or to * * bob's client if the operation completed or alice disconnected - * + * * @param client_session the associated client session * @return GNUNET_NO, if we could not notify the client * GNUNET_YES if we notified it. @@ -732,7 +779,7 @@ prepare_client_end_notification (void * cls, { struct ServiceSession * session = cls; struct GNUNET_SCALARPRODUCT_client_response * msg; - + session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; msg = GNUNET_new (struct GNUNET_SCALARPRODUCT_client_response); @@ -740,10 +787,10 @@ prepare_client_end_notification (void * cls, memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode)); memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity)); msg->header.size = htons (sizeof (struct GNUNET_SCALARPRODUCT_client_response)); - // 0 size and the first char in the product is 0, which should never be zero if encoding is used. + // signal error if not signalized, positive result-range field but zero length. msg->product_length = htonl (0); - msg->range = 1; - + msg->range = (session->state == FINALIZED) ? 0 : -1; + session->msg = &msg->header; //transmit this message to our client @@ -755,45 +802,117 @@ prepare_client_end_notification (void * cls, session); // if we could not even queue our request, something is wrong - if ( NULL == session->client_transmit_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client); - // usually gets freed by do_send_message - session->msg = NULL; - GNUNET_free (msg); - } + if (NULL == session->client_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to client (%p)!\n"), session->client); + // usually gets freed by do_send_message + session->msg = NULL; + GNUNET_free (msg); + } else GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->key)); - + } +static void +prepare_service_response_multipart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceSession * session = cls; + unsigned char * current; + unsigned char * element_exported; + struct GNUNET_SCALARPRODUCT_multipart_message * msg; + unsigned int i; + uint32_t msg_length; + uint32_t todo_count; + size_t element_length = 0; // initialized by gcry_mpi_print, but the compiler doesn't know that + + msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message); + todo_count = session->used - session->transferred; + + if (todo_count > MULTIPART_ELEMENT_CAPACITY / 2) + // send the currently possible maximum chunk, we always transfer both permutations + todo_count = MULTIPART_ELEMENT_CAPACITY / 2; + + msg_length += todo_count * PAILLIER_ELEMENT_LENGTH * 2; + msg = GNUNET_malloc (msg_length); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB_MULTIPART); + msg->header.size = htons (msg_length); + msg->multipart_element_count = htonl (todo_count); + + element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); + current = (unsigned char *) &msg[1]; + // convert k[][] + for (i = session->transferred; i < session->transferred + todo_count; i++) { + //k[i][p] + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + session->r[i])); + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; + //k[i][q] + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + session->r_prime[i])); + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; + } + GNUNET_free (element_exported); + for (i = session->transferred; i < session->transferred; i++) { + gcry_mpi_release (session->r_prime[i]); + gcry_mpi_release (session->r[i]); + } + session->transferred += todo_count; + session->msg = (struct GNUNET_MessageHeader *) msg; + session->service_transmit_handle = + GNUNET_MESH_notify_transmit_ready (session->tunnel, + GNUNET_YES, + GNUNET_TIME_UNIT_FOREVER_REL, + msg_length, + &do_send_message, + session); + //disconnect our client + if (NULL == session->service_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n")); + session->state = FINALIZED; + + session->response->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session->response); + return; + } + if (session->transferred != session->used) + // multipart + session->state = WAITING_FOR_MULTIPART_TRANSMISSION; + else + //singlepart + session->state = FINALIZED; +} /** * Bob executes: - * generates the response message to be sent to alice after computing + * generates the response message to be sent to alice after computing * the values (1), (2), S and S' * (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$ * (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ * S: $S := E_A(sum (r_i + b_i)^2)$ * S': $S' := E_A(sum r_i^2)$ - * - * @param r (1)[]: $E_A(a_{pi(i)}) times E_A(- r_{pi(i)} - b_{pi(i)}) &= E_A(a_{pi(i)} - r_{pi(i)} - b_{pi(i)})$ - * @param r_prime (2)[]: $E_A(a_{pi'(i)}) times E_A(- r_{pi'(i)}) &= E_A(a_{pi'(i)} - r_{pi'(i)})$ + * * @param s S: $S := E_A(sum (r_i + b_i)^2)$ * @param s_prime S': $S' := E_A(sum r_i^2)$ - * @param request the associated requesting session with alice - * @param response the associated responder session with bob's client - * @return GNUNET_SYSERR if the function was called with NULL parameters or if there was an error - * GNUNET_NO if we could not send our message + * @param session the associated requesting session with alice + * @return GNUNET_NO if we could not send our message * GNUNET_OK if the operation succeeded */ static int -prepare_service_response (gcry_mpi_t * r, - gcry_mpi_t * r_prime, - gcry_mpi_t s, +prepare_service_response (gcry_mpi_t s, gcry_mpi_t s_prime, - struct ServiceSession * request, - struct ServiceSession * response) + struct ServiceSession * session) { struct GNUNET_SCALARPRODUCT_service_response * msg; uint32_t msg_length = 0; @@ -803,114 +922,116 @@ prepare_service_response (gcry_mpi_t * r, int i; msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_response) - + 2 * request->used_element_count * PAILLIER_ELEMENT_LENGTH // kp, kq + 2 * PAILLIER_ELEMENT_LENGTH; // s, stick + if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length + 2 * session->used * PAILLIER_ELEMENT_LENGTH) { //kp, kq + msg_length += +2 * session->used * PAILLIER_ELEMENT_LENGTH; + session->transferred = session->used; + } + else { + session->transferred = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) / (PAILLIER_ELEMENT_LENGTH * 2); + } + msg = GNUNET_malloc (msg_length); msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE); msg->header.size = htons (msg_length); - msg->element_count = htonl (request->element_count); - msg->used_element_count = htonl (request->used_element_count); - memcpy (&msg->key, &request->key, sizeof (struct GNUNET_HashCode)); + msg->total_element_count = htonl (session->total); + msg->contained_element_count = htonl (session->used); + msg->contained_element_count = htonl (session->transferred); + memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode)); current = (unsigned char *) &msg[1]; + element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); // 4 times the same logics with slight variations. // doesn't really justify having 2 functions for that - // so i put it into blocks to enhance readability + // so i put it into blocks to enhance readability // convert s - { - element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + s)); + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; + + // convert stick + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + s_prime)); + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; + + // convert k[][] + for (i = 0; i < session->transferred; i++) { + //k[i][p] + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, element_exported, PAILLIER_ELEMENT_LENGTH, &element_length, - s)); + session->r[i])); adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); - GNUNET_free (element_exported); current += PAILLIER_ELEMENT_LENGTH; - } - - // convert stick - { - element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); + //k[i][q] + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, element_exported, PAILLIER_ELEMENT_LENGTH, &element_length, - s_prime)); + session->r_prime[i])); adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); - GNUNET_free (element_exported); current += PAILLIER_ELEMENT_LENGTH; } - // convert kp[] - for (i = 0; i < request->used_element_count; i++) - { - element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); - GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, - element_exported, PAILLIER_ELEMENT_LENGTH, - &element_length, - r[i])); - adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); - memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); - GNUNET_free (element_exported); - current += PAILLIER_ELEMENT_LENGTH; - } - - - // convert kq[] - for (i = 0; i < request->used_element_count; i++) - { - element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); - GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, - element_exported, PAILLIER_ELEMENT_LENGTH, - &element_length, - r_prime[i])); - adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); - memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); - GNUNET_free (element_exported); - current += PAILLIER_ELEMENT_LENGTH; - } + GNUNET_free (element_exported); + for (i = 0; i < session->transferred; i++) { + gcry_mpi_release (session->r_prime[i]); + gcry_mpi_release (session->r[i]); + } + gcry_mpi_release (s); + gcry_mpi_release (s_prime); - if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= msg_length) - { - request->msg = (struct GNUNET_MessageHeader *) msg; - request->service_transmit_handle = - GNUNET_MESH_notify_transmit_ready (request->tunnel, - GNUNET_YES, - GNUNET_TIME_UNIT_FOREVER_REL, - msg_length, - &do_send_message, - request); - // we don't care if it could be send or not. either way, the session is over for us. - request->state = FINALIZED; - } + session->msg = (struct GNUNET_MessageHeader *) msg; + session->service_transmit_handle = + GNUNET_MESH_notify_transmit_ready (session->tunnel, + GNUNET_YES, + GNUNET_TIME_UNIT_FOREVER_REL, + msg_length, + &do_send_message, + session); + //disconnect our client + if (NULL == session->service_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n")); + session->state = FINALIZED; + + session->response->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session->response); + return GNUNET_NO; + } + if (session->transferred != session->used) + // multipart + session->state = WAITING_FOR_MULTIPART_TRANSMISSION; else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!)\n")); + //singlepart + session->state = FINALIZED; - //disconnect our client - if ( NULL == request->service_transmit_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n")); - - response->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, - response); - return GNUNET_NO; - } return GNUNET_OK; } - /** - * executed by bob: - * compute the values + * executed by bob: + * compute the values * (1)[]: $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$ * (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$ * S: $S := E_A(\sum (r_i + b_i)^2)$ * S': $S' := E_A(\sum r_i^2)$ - * + * * @param request the requesting session + bob's requesting peer * @param response the responding session + bob's client handle * @return GNUNET_SYSERR if the computation failed @@ -943,7 +1064,7 @@ compute_service_response (struct ServiceSession * request, gcry_sexp_t tmp_exp; uint32_t value; - count = request->used_element_count; + count = request->used; b = GNUNET_malloc (sizeof (gcry_mpi_t) * count); a_pi = GNUNET_malloc (sizeof (gcry_mpi_t) * count); @@ -953,62 +1074,54 @@ compute_service_response (struct ServiceSession * request, rand_pi_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count); // convert responder session to from long to mpi - for (i = 0, j = 0; i < response->element_count && j < count; i++) - { - if (request->mask[i / 8] & (1 << (i % 8))) - { - value = response->vector[i] >= 0 ? response->vector[i] : -response->vector[i]; - // long to gcry_mpi_t - if (0 > response->vector[i]) - { - b[j] = gcry_mpi_new (0); - gcry_mpi_sub_ui (b[j], b[j], value); - } - else - { - b[j] = gcry_mpi_set_ui (NULL, value); - } - j++; - } + for (i = 0, j = 0; i < response->total && j < count; i++) { + if (request->mask[i / 8] & (1 << (i % 8))) { + value = response->vector[i] >= 0 ? response->vector[i] : -response->vector[i]; + // long to gcry_mpi_t + if (0 > response->vector[i]) { + b[j] = gcry_mpi_new (0); + gcry_mpi_sub_ui (b[j], b[j], value); + } + else { + b[j] = gcry_mpi_set_ui (NULL, value); + } + j++; } + } GNUNET_free (response->vector); response->vector = NULL; tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "n", 0); - if ( ! tmp_exp) - { - GNUNET_break_op (0); - gcry_sexp_release (request->remote_pubkey); - request->remote_pubkey = NULL; - goto except; - } + if (!tmp_exp) { + GNUNET_break_op (0); + gcry_sexp_release (request->remote_pubkey); + request->remote_pubkey = NULL; + goto except; + } remote_n = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG); - if ( ! remote_n) - { - GNUNET_break (0); - gcry_sexp_release (tmp_exp); - goto except; - } + if (!remote_n) { + GNUNET_break (0); + gcry_sexp_release (tmp_exp); + goto except; + } remote_nsquare = gcry_mpi_new (KEYBITS + 1); gcry_mpi_mul (remote_nsquare, remote_n, remote_n); gcry_sexp_release (tmp_exp); tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "g", 0); gcry_sexp_release (request->remote_pubkey); request->remote_pubkey = NULL; - if ( ! tmp_exp) - { - GNUNET_break_op (0); - gcry_mpi_release (remote_n); - goto except; - } + if (!tmp_exp) { + GNUNET_break_op (0); + gcry_mpi_release (remote_n); + goto except; + } remote_g = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG); - if ( ! remote_g) - { - GNUNET_break (0); - gcry_mpi_release (remote_n); - gcry_sexp_release (tmp_exp); - goto except; - } + if (!remote_g) { + GNUNET_break (0); + gcry_mpi_release (remote_n); + gcry_sexp_release (tmp_exp); + goto except; + } gcry_sexp_release (tmp_exp); // generate r, p and q @@ -1019,7 +1132,7 @@ compute_service_response (struct ServiceSession * request, r = initialize_mpi_vector (count); r_prime = initialize_mpi_vector (count); - // copy the REFERNCES of a, b and r into aq and bq. we will not change + // copy the REFERNCES of a, b and r into aq and bq. we will not change // those values, thus we can work with the references memcpy (a_pi, request->a, sizeof (gcry_mpi_t) * count); memcpy (a_pi_prime, request->a, sizeof (gcry_mpi_t) * count); @@ -1036,45 +1149,46 @@ compute_service_response (struct ServiceSession * request, // encrypt the element // for the sake of readability I decided to have dedicated permutation - // vectors, which get rid of all the lookups in p/q. + // vectors, which get rid of all the lookups in p/q. // however, ap/aq are not absolutely necessary but are just abstraction // Calculate Kp = E(S + a_pi) (+) E(S - r_pi - b_pi) - for (i = 0; i < count; i++) - { - // E(S - r_pi - b_pi) - gcry_mpi_sub (r[i], my_offset, rand_pi[i]); - gcry_mpi_sub (r[i], r[i], b_pi[i]); - encrypt_element (r[i], r[i], remote_g, remote_n, remote_nsquare); - - // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) - gcry_mpi_mulm (r[i], r[i], a_pi[i], remote_nsquare); - } + for (i = 0; i < count; i++) { + // E(S - r_pi - b_pi) + gcry_mpi_sub (r[i], my_offset, rand_pi[i]); + gcry_mpi_sub (r[i], r[i], b_pi[i]); + encrypt_element (r[i], r[i], remote_g, remote_n, remote_nsquare); + + // E(S - r_pi - b_pi) * E(S + a_pi) == E(2*S + a - r - b) + gcry_mpi_mulm (r[i], r[i], a_pi[i], remote_nsquare); + } GNUNET_free (a_pi); GNUNET_free (b_pi); GNUNET_free (rand_pi); // Calculate Kq = E(S + a_qi) (+) E(S - r_qi) - for (i = 0; i < count; i++) - { - // E(S - r_qi) - gcry_mpi_sub (r_prime[i], my_offset, rand_pi_prime[i]); - encrypt_element (r_prime[i], r_prime[i], remote_g, remote_n, remote_nsquare); + for (i = 0; i < count; i++) { + // E(S - r_qi) + gcry_mpi_sub (r_prime[i], my_offset, rand_pi_prime[i]); + encrypt_element (r_prime[i], r_prime[i], remote_g, remote_n, remote_nsquare); - // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) - gcry_mpi_mulm (r_prime[i], r_prime[i], a_pi_prime[i], remote_nsquare); - } + // E(S - r_qi) * E(S + a_qi) == E(2*S + a_qi - r_qi) + gcry_mpi_mulm (r_prime[i], r_prime[i], a_pi_prime[i], remote_nsquare); + } GNUNET_free (a_pi_prime); GNUNET_free (rand_pi_prime); + request->r = r; + request->r_prime = r_prime; + request->response = response; + // Calculate S' = E(SUM( r_i^2 )) s_prime = compute_square_sum (rand, count); encrypt_element (s_prime, s_prime, remote_g, remote_n, remote_nsquare); // Calculate S = E(SUM( (r_i + b_i)^2 )) - for (i = 0; i < count; i++) - { - gcry_mpi_add (rand[i], rand[i], b[i]); - } + for (i = 0; i < count; i++) { + gcry_mpi_add (rand[i], rand[i], b[i]); + } s = compute_square_sum (rand, count); encrypt_element (s, s, remote_g, remote_n, remote_nsquare); gcry_mpi_release (remote_n); @@ -1086,28 +1200,18 @@ compute_service_response (struct ServiceSession * request, // rp, rq, aq, ap, bp, bq are released along with a, r, b respectively, (a and b are handled at except:) gcry_mpi_release (rand[i]); - // copy the Kp[], Kq[], S and Stick into a new message - if (GNUNET_YES != prepare_service_response (r, r_prime, s, s_prime, request, response)) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to communicate with `%s', scalar product calculation aborted.\n"), - GNUNET_i2s (&request->peer)); + // copy the r[], r_prime[], S and Stick into a new message, prepare_service_response frees these + if (GNUNET_YES != prepare_service_response (s, s_prime, request)) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Failed to communicate with `%s', scalar product calculation aborted.\n"), + GNUNET_i2s (&request->peer)); else ret = GNUNET_OK; - for (i = 0; i < count; i++) - { - gcry_mpi_release (r_prime[i]); - gcry_mpi_release (r[i]); - } - - gcry_mpi_release (s); - gcry_mpi_release (s_prime); - except: - for (i = 0; i < count; i++) - { - gcry_mpi_release (b[i]); - gcry_mpi_release (request->a[i]); - } + for (i = 0; i < count; i++) { + gcry_mpi_release (b[i]); + gcry_mpi_release (request->a[i]); + } GNUNET_free (b); GNUNET_free (request->a); @@ -1116,10 +1220,107 @@ except: return ret; } +static void +prepare_service_request_multipart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ServiceSession * session = cls; + unsigned char * current; + unsigned char * element_exported; + struct GNUNET_SCALARPRODUCT_multipart_message * msg; + unsigned int i; + unsigned int j; + uint32_t msg_length; + uint32_t todo_count; + size_t element_length = 0; // initialized by gcry_mpi_print, but the compiler doesn't know that + gcry_mpi_t a; + uint32_t value; + + msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message); + todo_count = session->used - session->transferred; + + if (todo_count > MULTIPART_ELEMENT_CAPACITY) + // send the currently possible maximum chunk + todo_count = MULTIPART_ELEMENT_CAPACITY; + + msg_length += todo_count * PAILLIER_ELEMENT_LENGTH; + msg = GNUNET_malloc (msg_length); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB_MULTIPART); + msg->header.size = htons (msg_length); + msg->multipart_element_count = htonl (todo_count); + + element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); + a = gcry_mpi_new (KEYBITS * 2); + current = (unsigned char *) &msg[1]; + // encrypt our vector and generate string representations + for (i = session->last_processed, j = 0; i < session->total; i++) { + // is this a used element? + if (session->mask[i / 8] & 1 << (i % 8)) { + if (todo_count <= j) + break; //reached end of this message, can't include more + + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i]; + + a = gcry_mpi_set_ui (a, 0); + // long to gcry_mpi_t + if (session->vector[i] < 0) + gcry_mpi_sub_ui (a, a, value); + else + gcry_mpi_add_ui (a, a, value); + + session->a[session->transferred + j++] = gcry_mpi_set (NULL, a); + gcry_mpi_add (a, a, my_offset); + encrypt_element (a, a, my_g, my_n, my_nsquare); + + // get representation as string + // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory + GNUNET_assert (!gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + a)); + + // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + + // copy over to the message + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; + } + } + gcry_mpi_release (a); + GNUNET_free (element_exported); + session->transferred += todo_count; + + session->msg = (struct GNUNET_MessageHeader *) msg; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n")); + + //transmit via mesh messaging + session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready (session->tunnel, GNUNET_YES, + GNUNET_TIME_UNIT_FOREVER_REL, + msg_length, + &do_send_message, + session); + if (!session->service_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-request multipart message to tunnel!\n")); + GNUNET_free (msg); + session->msg = NULL; + session->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session); + return; + } + if (session->transferred != session->used) { + session->last_processed = i; + } + else + //final part + session->state = WAITING_FOR_SERVICE_RESPONSE; +} /** * Executed by Alice, fills in a service-request message and sends it to the given peer - * + * * @param session the session associated with this request, then also holds the CORE-handle * @return #GNUNET_SYSERR if we could not send the message * #GNUNET_NO if the message was too large @@ -1131,6 +1332,7 @@ prepare_service_request (void *cls, { struct ServiceSession * session = cls; unsigned char * current; + unsigned char * element_exported; struct GNUNET_SCALARPRODUCT_service_request * msg; unsigned int i; unsigned int j; @@ -1138,35 +1340,32 @@ prepare_service_request (void *cls, size_t element_length = 0; // initialized by gcry_mpi_print, but the compiler doesn't know that gcry_mpi_t a; uint32_t value; - + session->service_request_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new tunnel to peer (%s)!\n"), GNUNET_i2s (&session->peer)); msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_request) - + session->used_element_count * PAILLIER_ELEMENT_LENGTH - + session->mask_length + +session->mask_length + my_pubkey_external_length; - if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (struct GNUNET_SCALARPRODUCT_service_request) - + session->used_element_count * PAILLIER_ELEMENT_LENGTH - + session->mask_length - + my_pubkey_external_length) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n")); - session->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, - session); - return; - } - + if (GNUNET_SERVER_MAX_MESSAGE_SIZE > msg_length + session->used * PAILLIER_ELEMENT_LENGTH) { + msg_length += session->used * PAILLIER_ELEMENT_LENGTH; + session->transferred = session->used; + } + else { + //create a multipart msg, first we calculate a new msg size for the head msg + session->transferred = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - msg_length) / PAILLIER_ELEMENT_LENGTH; + } + msg = GNUNET_malloc (msg_length); msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB); + msg->total_element_count = htonl (session->used); + msg->contained_element_count = htonl (session->transferred); memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode)); msg->mask_length = htonl (session->mask_length); msg->pk_length = htonl (my_pubkey_external_length); - msg->used_element_count = htonl (session->used_element_count); - msg->element_count = htonl (session->element_count); + msg->element_count = htonl (session->total); msg->header.size = htons (msg_length); // fill in the payload @@ -1177,49 +1376,52 @@ prepare_service_request (void *cls, current += session->mask_length; memcpy (current, my_pubkey_external, my_pubkey_external_length); current += my_pubkey_external_length; - + // now copy over the element vector - session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used_element_count); + element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); + session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used); a = gcry_mpi_new (KEYBITS * 2); // encrypt our vector and generate string representations - for (i = 0, j = 0; i < session->element_count; i++) - { - // if this is a used element... - if (session->mask[i / 8] & 1 << (i % 8)) - { - unsigned char * element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH); - value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i]; - - a = gcry_mpi_set_ui (a, 0); - // long to gcry_mpi_t - if (session->vector[i] < 0) - gcry_mpi_sub_ui (a, a, value); - else - gcry_mpi_add_ui (a, a, value); - - session->a[j++] = gcry_mpi_set (NULL, a); - gcry_mpi_add (a, a, my_offset); - encrypt_element (a, a, my_g, my_n, my_nsquare); - - // get representation as string - // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory - GNUNET_assert ( ! gcry_mpi_print (GCRYMPI_FMT_USG, - element_exported, PAILLIER_ELEMENT_LENGTH, - &element_length, - a)); - - // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size - adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); - - // copy over to the message - memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); - current += PAILLIER_ELEMENT_LENGTH; - } + for (i = 0, j = 0; i < session->total; i++) { + // if this is a used element... + if (session->mask[i / 8] & 1 << (i % 8)) { + if (session->transferred <= j) + break; //reached end of this message, can't include more + + memset (element_exported, 0, PAILLIER_ELEMENT_LENGTH); + value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i]; + + a = gcry_mpi_set_ui (a, 0); + // long to gcry_mpi_t + if (session->vector[i] < 0) + gcry_mpi_sub_ui (a, a, value); + else + gcry_mpi_add_ui (a, a, value); + + session->a[j++] = gcry_mpi_set (NULL, a); + gcry_mpi_add (a, a, my_offset); + encrypt_element (a, a, my_g, my_n, my_nsquare); + + // get representation as string + // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory + GNUNET_assert (!gcry_mpi_print (GCRYMPI_FMT_USG, + element_exported, PAILLIER_ELEMENT_LENGTH, + &element_length, + a)); + + // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size + adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH); + + // copy over to the message + memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH); + current += PAILLIER_ELEMENT_LENGTH; } + } gcry_mpi_release (a); + GNUNET_free (element_exported); session->msg = (struct GNUNET_MessageHeader *) msg; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting service request.\n")); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Transmitting service request.\n")); //transmit via mesh messaging session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready (session->tunnel, GNUNET_YES, @@ -1227,24 +1429,29 @@ prepare_service_request (void *cls, msg_length, &do_send_message, session); - if ( ! session->service_transmit_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not send mutlicast message to tunnel!\n")); - GNUNET_free (msg); - session->msg = NULL; - session->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, - session); - return; - } - session->state = WAITING_FOR_SERVICE_RESPONSE; + if (!session->service_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send message to tunnel!\n")); + GNUNET_free (msg); + session->msg = NULL; + session->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session); + return; + } + if (session->transferred != session->used) { + session->state = WAITING_FOR_MULTIPART_TRANSMISSION; + session->last_processed = i; + } + else + //singlepart message + session->state = WAITING_FOR_SERVICE_RESPONSE; } /** - * Handler for a client request message. + * Handler for a client request message. * Can either be type A or B * A: request-initiation to compute a scalar product with a peer - * B: response role, keep the values + session and wait for a matching session or process a waiting request + * B: response role, keep the values + session and wait for a matching session or process a waiting request * * @param cls closure * @param client identification of the client @@ -1265,57 +1472,54 @@ handle_client_request (void *cls, // only one concurrent session per client connection allowed, simplifies logics a lot... session = GNUNET_SERVER_client_get_user_context (client, struct ServiceSession); - if ((NULL != session) && (session->state != FINALIZED)){ + if ((NULL != session) && (session->state != FINALIZED)) { GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } - else if(NULL != session){ + else if (NULL != session) { // old session is already completed, clean it up GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session); - free_session(session); + free_session (session); } //we need at least a peer and one message id to compare - if (sizeof (struct GNUNET_SCALARPRODUCT_client_request) > ntohs (msg->header.size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ ("Too short message received from client!\n")); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + if (sizeof (struct GNUNET_SCALARPRODUCT_client_request) > ntohs (msg->header.size)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ ("Too short message received from client!\n")); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } msg_type = ntohs (msg->header.type); element_count = ntohl (msg->element_count); mask_length = ntohl (msg->mask_length); //sanity check: is the message as long as the message_count fields suggests? - if (( ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_client_request) + element_count * sizeof (int32_t) + mask_length)) - || (0 == element_count)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ ("Invalid message received from client, session information incorrect!\n")); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + if ((ntohs (msg->header.size) != (sizeof (struct GNUNET_SCALARPRODUCT_client_request) +element_count * sizeof (int32_t) + mask_length)) + || (0 == element_count)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ ("Invalid message received from client, session information incorrect!\n")); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } // do we have a duplicate session here already? if (NULL != find_matching_session (from_client_tail, &msg->key, element_count, - NULL, NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ ("Duplicate session information received, cannot create new session with key `%s'\n"), - GNUNET_h2s (&msg->key)); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } + NULL, NULL)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ ("Duplicate session information received, cannot create new session with key `%s'\n"), + GNUNET_h2s (&msg->key)); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } session = GNUNET_new (struct ServiceSession); session->service_request_task = GNUNET_SCHEDULER_NO_TASK; session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; session->client = client; - session->element_count = element_count; + session->total = element_count; session->mask_length = mask_length; // get our transaction key memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode)); @@ -1323,115 +1527,107 @@ handle_client_request (void *cls, session->vector = GNUNET_malloc (sizeof (int32_t) * element_count); vector = (int32_t *) & msg[1]; - if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ ("Got client-request-session with key %s, preparing tunnel to remote service.\n"), - GNUNET_h2s (&session->key)); - - session->role = ALICE; - // fill in the mask - session->mask = GNUNET_malloc (mask_length); - memcpy (session->mask, &vector[element_count], mask_length); - - // copy over the elements - session->used_element_count = 0; - for (i = 0; i < element_count; i++) - { - session->vector[i] = ntohl (vector[i]); - if (session->vector[i] == 0) - session->mask[i / 8] &= ~(1 << (i % 8)); - if (session->mask[i / 8] & (1 << (i % 8))) - session->used_element_count++; - } + if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE == msg_type) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ ("Got client-request-session with key %s, preparing tunnel to remote service.\n"), + GNUNET_h2s (&session->key)); + + session->role = ALICE; + // fill in the mask + session->mask = GNUNET_malloc (mask_length); + memcpy (session->mask, &vector[element_count], mask_length); + + // copy over the elements + session->used = 0; + for (i = 0; i < element_count; i++) { + session->vector[i] = ntohl (vector[i]); + if (session->vector[i] == 0) + session->mask[i / 8] &= ~(1 << (i % 8)); + if (session->mask[i / 8] & (1 << (i % 8))) + session->used++; + } - if ( 0 == session->used_element_count) - { - GNUNET_break_op (0); - GNUNET_free (session->vector); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - //session with ourself makes no sense! - if ( ! memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_break (0); - GNUNET_free (session->vector); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - // get our peer ID - memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity)); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ ("Creating new tunnel to for session with key %s.\n"), - GNUNET_h2s (&session->key)); - session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session, - &session->peer, - GNUNET_APPLICATION_TYPE_SCALARPRODUCT, - GNUNET_NO, - GNUNET_YES); - //prepare_service_request, tunnel_peer_disconnect_handler, - if ( ! session->tunnel) - { - GNUNET_break (0); - GNUNET_free (session->vector); - GNUNET_free (session); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - GNUNET_SERVER_client_set_user_context (client, session); - GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session); - - session->state = CLIENT_REQUEST_RECEIVED; - session->service_request_task = - GNUNET_SCHEDULER_add_now (&prepare_service_request, + if (0 == session->used) { + GNUNET_break_op (0); + GNUNET_free (session->vector); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + //session with ourself makes no sense! + if (!memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity))) { + GNUNET_break (0); + GNUNET_free (session->vector); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + // get our peer ID + memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ ("Creating new tunnel to for session with key %s.\n"), + GNUNET_h2s (&session->key)); + session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session, + &session->peer, + GNUNET_APPLICATION_TYPE_SCALARPRODUCT, + GNUNET_NO, + GNUNET_YES); + //prepare_service_request, tunnel_peer_disconnect_handler, + if (!session->tunnel) { + GNUNET_break (0); + GNUNET_free (session->vector); + GNUNET_free (session); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_client_set_user_context (client, session); + GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session); + + session->state = CLIENT_REQUEST_RECEIVED; + session->service_request_task = + GNUNET_SCHEDULER_add_now (&prepare_service_request, + session); + + } + else { + struct ServiceSession * requesting_session; + enum SessionState needed_state = SERVICE_REQUEST_RECEIVED; + + session->role = BOB; + session->mask = NULL; + // copy over the elements + session->used = element_count; + for (i = 0; i < element_count; i++) + session->vector[i] = ntohl (vector[i]); + session->state = CLIENT_RESPONSE_RECEIVED; + + GNUNET_SERVER_client_set_user_context (client, session); + GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session); + + //check if service queue contains a matching request + requesting_session = find_matching_session (from_service_tail, + &session->key, + session->total, + &needed_state, NULL); + if (NULL != requesting_session) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"), GNUNET_h2s (&session->key)); + if (GNUNET_OK != compute_service_response (requesting_session, session)) + session->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, session); - + } - else - { - struct ServiceSession * requesting_session; - enum SessionState needed_state = SERVICE_REQUEST_RECEIVED; - - session->role = BOB; - session->mask = NULL; - // copy over the elements - session->used_element_count = element_count; - for (i = 0; i < element_count; i++) - session->vector[i] = ntohl (vector[i]); - session->state = CLIENT_RESPONSE_RECEIVED; - - GNUNET_SERVER_client_set_user_context (client, session); - GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session); - - //check if service queue contains a matching request - requesting_session = find_matching_session (from_service_tail, - &session->key, - session->element_count, - &needed_state, NULL); - if (NULL != requesting_session) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s and a matching service-request-session set, processing.\n"), GNUNET_h2s (&session->key)); - if (GNUNET_OK != compute_service_response (requesting_session, session)) - session->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, - session); - - } - else{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"), GNUNET_h2s (&session->key)); - // no matching session exists yet, store the response - // for later processing by handle_service_request() - } + else { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session with key %s but NO matching service-request-session set, queuing element for later use.\n"), GNUNET_h2s (&session->key)); + // no matching session exists yet, store the response + // for later processing by handle_service_request() } + } GNUNET_SERVER_receive_done (client, GNUNET_YES); } - /** - * Function called for inbound tunnels. + * Function called for inbound tunnels. * * @param cls closure * @param tunnel new handle to the tunnel @@ -1441,7 +1637,7 @@ handle_client_request (void *cls, * (can be NULL -- that's not an error) */ static void * -tunnel_incoming_handler (void *cls, +tunnel_incoming_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_PeerIdentity *initiator, uint32_t port) @@ -1455,11 +1651,10 @@ tunnel_incoming_handler (void *cls, return c; } - /** * Function called whenever a tunnel is destroyed. Should clean up - * any associated state. - * + * any associated state. + * * It must NOT call GNUNET_MESH_tunnel_destroy on the tunnel. * * @param cls closure (set from GNUNET_MESH_connect) @@ -1475,31 +1670,28 @@ tunnel_destruction_handler (void *cls, struct ServiceSession * session = tunnel_ctx; struct ServiceSession * client_session; struct ServiceSession * curr; - + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Peer disconnected, terminating session %s with peer (%s)\n"), - GNUNET_h2s (&session->key), - GNUNET_i2s (&session->peer)); + _ ("Peer disconnected, terminating session %s with peer (%s)\n"), + GNUNET_h2s (&session->key), + GNUNET_i2s (&session->peer)); if (ALICE == session->role) { // as we have only one peer connected in each session, just remove the session - if ((SERVICE_RESPONSE_RECEIVED > session->state) && (!do_shutdown)) - { + if ((SERVICE_RESPONSE_RECEIVED > session->state) && (!do_shutdown)) { session->tunnel = NULL; // if this happened before we received the answer, we must terminate the session - session->client_notification_task = + session->client_notification_task = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, session); } } else { //(BOB == session->role) service session - // remove the session, unless it has already been dequeued, but somehow still active // this could bug without the IF in case the queue is empty and the service session was the only one know to the service // scenario: disconnect before alice can send her message to bob. for (curr = from_service_head; NULL != curr; curr = curr->next) - if (curr == session) - { + if (curr == session) { GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr); break; } @@ -1507,39 +1699,37 @@ tunnel_destruction_handler (void *cls, // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either. client_session = find_matching_session (from_client_tail, &session->key, - session->element_count, + session->total, NULL, NULL); free_session (session); - // the client has to check if it was waiting for a result + // the client has to check if it was waiting for a result // or if it was a responder, no point in adding more statefulness - if (client_session && (!do_shutdown)) - { - client_session->client_notification_task = + if (client_session && (!do_shutdown)) { + client_session->state = FINALIZED; + client_session->client_notification_task = GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, client_session); } } } - /** * Compute our scalar product, done by Alice - * + * * @param session - the session associated with this computation - * @param kp - (1) from the protocol definition: + * @param kp - (1) from the protocol definition: * $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$ - * @param kq - (2) from the protocol definition: + * @param kq - (2) from the protocol definition: * $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$ - * @param s - S from the protocol definition: + * @param s - S from the protocol definition: * $S := E_A(\sum (r_i + b_i)^2)$ - * @param stick - S' from the protocol definition: + * @param stick - S' from the protocol definition: * $S' := E_A(\sum r_i^2)$ * @return product as MPI, never NULL */ static gcry_mpi_t -compute_scalar_product (struct ServiceSession * session, - gcry_mpi_t * r, gcry_mpi_t * r_prime, gcry_mpi_t s, gcry_mpi_t s_prime) +compute_scalar_product (struct ServiceSession * session) { uint32_t count; gcry_mpi_t t; @@ -1550,48 +1740,47 @@ compute_scalar_product (struct ServiceSession * session, gcry_mpi_t tmp; unsigned int i; - count = session->used_element_count; + count = session->used; tmp = gcry_mpi_new (KEYBITS); // due to the introduced static offset S, we now also have to remove this // from the E(a_pi)(+)E(-b_pi-r_pi) and E(a_qi)(+)E(-r_qi) twice each, // the result is E((S + a_pi) + (S -b_pi-r_pi)) and E(S + a_qi + S - r_qi) - for (i = 0; i < count; i++) - { - decrypt_element (r[i], r[i], my_mu, my_lambda, my_n, my_nsquare); - gcry_mpi_sub(r[i],r[i],my_offset); - gcry_mpi_sub(r[i],r[i],my_offset); - decrypt_element (r_prime[i], r_prime[i], my_mu, my_lambda, my_n, my_nsquare); - gcry_mpi_sub(r_prime[i],r_prime[i],my_offset); - gcry_mpi_sub(r_prime[i],r_prime[i],my_offset); - } + for (i = 0; i < count; i++) { + decrypt_element (session->r[i], session->r[i], my_mu, my_lambda, my_n, my_nsquare); + gcry_mpi_sub (session->r[i], session->r[i], my_offset); + gcry_mpi_sub (session->r[i], session->r[i], my_offset); + decrypt_element (session->r_prime[i], session->r_prime[i], my_mu, my_lambda, my_n, my_nsquare); + gcry_mpi_sub (session->r_prime[i], session->r_prime[i], my_offset); + gcry_mpi_sub (session->r_prime[i], session->r_prime[i], my_offset); + } // calculate t = sum(ai) t = compute_square_sum (session->a, count); // calculate U u = gcry_mpi_new (0); - tmp = compute_square_sum (r, count); + tmp = compute_square_sum (session->r, count); gcry_mpi_sub (u, u, tmp); gcry_mpi_release (tmp); //calculate U' utick = gcry_mpi_new (0); - tmp = compute_square_sum (r_prime, count); + tmp = compute_square_sum (session->r_prime, count); gcry_mpi_sub (utick, utick, tmp); GNUNET_assert (p = gcry_mpi_new (0)); GNUNET_assert (ptick = gcry_mpi_new (0)); // compute P - decrypt_element (s, s, my_mu, my_lambda, my_n, my_nsquare); - decrypt_element (s_prime, s_prime, my_mu, my_lambda, my_n, my_nsquare); - + decrypt_element (session->s, session->s, my_mu, my_lambda, my_n, my_nsquare); + decrypt_element (session->s_prime, session->s_prime, my_mu, my_lambda, my_n, my_nsquare); + // compute P - gcry_mpi_add (p, s, t); + gcry_mpi_add (p, session->s, t); gcry_mpi_add (p, p, u); // compute P' - gcry_mpi_add (ptick, s_prime, t); + gcry_mpi_add (ptick, session->s_prime, t); gcry_mpi_add (ptick, ptick, utick); gcry_mpi_release (t); @@ -1609,15 +1798,14 @@ compute_scalar_product (struct ServiceSession * session, gcry_mpi_release (session->a[i]); GNUNET_free (session->a); session->a = NULL; - + return p; } - /** * prepare the response we will send to alice or bobs' clients. - * in Bobs case the product will be NULL. - * + * in Bobs case the product will be NULL. + * * @param session the session associated with our client. */ static void @@ -1632,81 +1820,180 @@ prepare_client_response (void *cls, int8_t range = -1; gcry_error_t rc; int sign; - + session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; - if (session->product) - { - gcry_mpi_t value = gcry_mpi_new(0); - - sign = gcry_mpi_cmp_ui(session->product, 0); - // libgcrypt can not handle a print of a negative number - // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ - if (0 > sign){ - gcry_mpi_sub(value, value, session->product); - } - else if(0 < sign){ - range = 1; - gcry_mpi_add(value, value, session->product); - } - else - range = 0; - - gcry_mpi_release (session->product); - session->product = NULL; - - // get representation as string - if (range - && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_USG, - &product_exported, - &product_length, - value)))){ - LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - product_length = 0; - range = -1; // signal error with product-length = 0 and range = -1 - } - gcry_mpi_release (value); + if (session->product) { + gcry_mpi_t value = gcry_mpi_new (0); + + sign = gcry_mpi_cmp_ui (session->product, 0); + // libgcrypt can not handle a print of a negative number + // if (a->sign) return gcry_error (GPG_ERR_INTERNAL); /* Can't handle it yet. */ + if (0 > sign) { + gcry_mpi_sub (value, value, session->product); + } + else if (0 < sign) { + range = 1; + gcry_mpi_add (value, value, session->product); + } + else + range = 0; + + gcry_mpi_release (session->product); + session->product = NULL; + + // get representation as string + if (range + && (0 != (rc = gcry_mpi_aprint (GCRYMPI_FMT_STD, + &product_exported, + &product_length, + value)))) { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + product_length = 0; + range = -1; // signal error with product-length = 0 and range = -1 } + gcry_mpi_release (value); + } - msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) + product_length; + msg_length = sizeof (struct GNUNET_SCALARPRODUCT_client_response) +product_length; msg = GNUNET_malloc (msg_length); memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode)); memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity)); - if (product_exported != NULL){ + if (product_exported != NULL) { memcpy (&msg[1], product_exported, product_length); - GNUNET_free(product_exported); + GNUNET_free (product_exported); } msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT); msg->header.size = htons (msg_length); msg->range = range; msg->product_length = htonl (product_length); - + session->msg = (struct GNUNET_MessageHeader *) msg; //transmit this message to our client - session->client_transmit_handle = + session->client_transmit_handle = GNUNET_SERVER_notify_transmit_ready (session->client, msg_length, GNUNET_TIME_UNIT_FOREVER_REL, &do_send_message, session); - if ( NULL == session->client_transmit_handle) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ ("Could not send message to client (%p)!\n"), - session->client); - session->client = NULL; - // callback was not called! - GNUNET_free (msg); - session->msg = NULL; - } + if (NULL == session->client_transmit_handle) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ ("Could not send message to client (%p)!\n"), + session->client); + session->client = NULL; + // callback was not called! + GNUNET_free (msg); + session->msg = NULL; + } else - // gracefully sent message, just terminate session structure - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ ("Sent result to client (%p), this session (%s) has ended!\n"), - session->client, - GNUNET_h2s (&session->key)); + // gracefully sent message, just terminate session structure + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _ ("Sent result to client (%p), this session (%s) has ended!\n"), + session->client, + GNUNET_h2s (&session->key)); } +/** + * Handle a multipart-chunk of a request from another service to calculate a scalarproduct with us. + * + * @param cls closure (set from #GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_service_request_multipart (void *cls, + struct GNUNET_MESH_Tunnel * tunnel, + void **tunnel_ctx, + const struct GNUNET_MessageHeader * message) +{ + struct ServiceSession * session; + const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message; + uint32_t used_elements; + uint32_t contained_elements=0; + uint32_t msg_length; + unsigned char * current; + int32_t i = -1; + + // are we in the correct state? + session = (struct ServiceSession *) * tunnel_ctx; + if ((BOB != session->role) || (WAITING_FOR_MULTIPART_TRANSMISSION != session->state)) { + goto except; + } + // shorter than minimum? + if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) { + goto except; + } + used_elements = session->used; + contained_elements = ntohl (msg->multipart_element_count); + msg_length = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message) + + contained_elements * PAILLIER_ELEMENT_LENGTH; + //sanity check + if (( ntohs (msg->header.size) != msg_length) + || (used_elements < contained_elements + session->transferred)) { + goto except; + } + current = (unsigned char *) &msg[1]; + if (contained_elements != 0) { + gcry_error_t ret = 0; + // Convert each vector element to MPI_value + for (i = session->transferred; i < session->transferred+contained_elements; i++) { + size_t read = 0; + + ret = gcry_mpi_scan (&session->a[i], + GCRYMPI_FMT_USG, + ¤t[i * PAILLIER_ELEMENT_LENGTH], + PAILLIER_ELEMENT_LENGTH, + &read); + if (ret) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate E[a%d] to MPI!\n%s/%s\n"), + i, gcry_strsource (ret), gcry_strerror (ret)); + goto except; + } + } + session->transferred+=contained_elements; + + if (session->transferred == used_elements) { + // single part finished + session->state = SERVICE_REQUEST_RECEIVED; + if (session->response) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->key)); + if (GNUNET_OK != compute_service_response (session, session->response)) { + //something went wrong, remove it again... + GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session); + goto except; + } + } + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->key)); + } + else{ + // multipart message + } + } + + return GNUNET_OK; +except: + for (i = 0; i < session->used; i++) + if (session->a[i]) + gcry_mpi_release (session->a[i]); + gcry_sexp_release (session->remote_pubkey); + session->remote_pubkey = NULL; + GNUNET_free (session->a); + session->a = NULL; + free_session (session); + // and notify our client-session that we could not complete the session + if (session->response) + // we just found the responder session in this queue + session->response->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session->response); + return GNUNET_SYSERR; +} /** * Handle a request from another service to calculate a scalarproduct with us. @@ -1731,70 +2018,60 @@ handle_service_request (void *cls, uint32_t mask_length; uint32_t pk_length; uint32_t used_elements; + uint32_t contained_elements = 0; uint32_t element_count; uint32_t msg_length; unsigned char * current; - struct ServiceSession * responder_session; int32_t i = -1; enum SessionState needed_state; session = (struct ServiceSession *) * tunnel_ctx; - if (BOB != session->role){ - GNUNET_break_op(0); - return GNUNET_SYSERR; + if (WAITING_FOR_SERVICE_REQUEST != session->state) { + GNUNET_break_op (0); + goto except; } - // is this tunnel already in use? - if ( (session->next) || (from_service_head == session)) - { - GNUNET_break_op(0); - return GNUNET_SYSERR; - } // Check if message was sent by me, which would be bad! - if ( ! memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) - { - GNUNET_free (session); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - //we need at least a peer and one message id to compare - if (ntohs (msg->header.size) < sizeof (struct GNUNET_SCALARPRODUCT_service_request)) - { - GNUNET_free (session); - GNUNET_break_op(0); - return GNUNET_SYSERR; - } + if (!memcmp (&session->peer, &me, sizeof (struct GNUNET_PeerIdentity))) { + GNUNET_free (session); + GNUNET_break (0); + return GNUNET_SYSERR; + } + // shorter than expected? + if (ntohs (msg->header.size) < sizeof (struct GNUNET_SCALARPRODUCT_service_request)) { + GNUNET_free (session); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } mask_length = ntohl (msg->mask_length); pk_length = ntohl (msg->pk_length); - used_elements = ntohl (msg->used_element_count); + used_elements = ntohl (msg->total_element_count); + contained_elements = ntohl (msg->contained_element_count); element_count = ntohl (msg->element_count); msg_length = sizeof (struct GNUNET_SCALARPRODUCT_service_request) - + mask_length + pk_length + used_elements * PAILLIER_ELEMENT_LENGTH; + +mask_length + pk_length + contained_elements * PAILLIER_ELEMENT_LENGTH; //sanity check: is the message as long as the message_count fields suggests? - if ((ntohs (msg->header.size) != msg_length) || (element_count < used_elements) + if ((ntohs (msg->header.size) != msg_length) || (element_count < used_elements) || (used_elements < contained_elements) || (used_elements == 0) || (mask_length != (element_count / 8 + (element_count % 8 ? 1 : 0))) - ) - { - GNUNET_free (session); - GNUNET_break_op(0); - return GNUNET_SYSERR; - } + ) { + GNUNET_free (session); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } if (find_matching_session (from_service_tail, &msg->key, element_count, NULL, - NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"), (const char *) &(msg->key)); - GNUNET_free (session); - return GNUNET_SYSERR; - } - + NULL)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"), (const char *) &(msg->key)); + GNUNET_free (session); + return GNUNET_SYSERR; + } + memcpy (&session->peer, &session->peer, sizeof (struct GNUNET_PeerIdentity)); - session->state = SERVICE_REQUEST_RECEIVED; - session->element_count = ntohl (msg->element_count); - session->used_element_count = used_elements; + session->total = element_count; + session->used = used_elements; + session->transferred = contained_elements; session->tunnel = tunnel; // session key @@ -1807,89 +2084,174 @@ handle_service_request (void *cls, current += mask_length; //convert the publickey to sexp - if (gcry_sexp_new (&session->remote_pubkey, current, pk_length, 1)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate remote public key to sexpression!\n")); - GNUNET_free (session->mask); - GNUNET_free (session); - return GNUNET_SYSERR; - } + if (gcry_sexp_new (&session->remote_pubkey, current, pk_length, 1)) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate remote public key to sexpression!\n")); + GNUNET_free (session->mask); + GNUNET_free (session); + return GNUNET_SYSERR; + } current += pk_length; - //check if service queue contains a matching request + //check if service queue contains a matching request needed_state = CLIENT_RESPONSE_RECEIVED; - responder_session = find_matching_session (from_client_tail, + session->response = find_matching_session (from_client_tail, &session->key, - session->element_count, + session->total, &needed_state, NULL); session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements); - - if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_SCALARPRODUCT_service_request) - +pk_length - + mask_length - + used_elements * PAILLIER_ELEMENT_LENGTH) - { - gcry_error_t ret = 0; - session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements); - // Convert each vector element to MPI_value - for (i = 0; i < used_elements; i++) - { - size_t read = 0; - - ret = gcry_mpi_scan (&session->a[i], - GCRYMPI_FMT_USG, - ¤t[i * PAILLIER_ELEMENT_LENGTH], - PAILLIER_ELEMENT_LENGTH, - &read); - if (ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate E[a%d] to MPI!\n%s/%s\n"), - i, gcry_strsource (ret), gcry_strerror (ret)); - goto except; - } - } - GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session); - if (responder_session) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->key)); - if (GNUNET_OK != compute_service_response (session, responder_session)) - { - //something went wrong, remove it again... - GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session); - goto except; - } + session->state = WAITING_FOR_MULTIPART_TRANSMISSION; + if (contained_elements != 0) { + gcry_error_t ret = 0; + // Convert each vector element to MPI_value + for (i = 0; i < contained_elements; i++) { + size_t read = 0; + + ret = gcry_mpi_scan (&session->a[i], + GCRYMPI_FMT_USG, + ¤t[i * PAILLIER_ELEMENT_LENGTH], + PAILLIER_ELEMENT_LENGTH, + &read); + if (ret) { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate E[a%d] to MPI!\n%s/%s\n"), + i, gcry_strsource (ret), gcry_strerror (ret)); + goto except; + } + } + GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session); + + if (contained_elements == used_elements) { + // single part finished + session->state = SERVICE_REQUEST_RECEIVED; + if (session->response) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->key)); + if (GNUNET_OK != compute_service_response (session, session->response)) { + //something went wrong, remove it again... + GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session); + goto except; } + } else - GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->key)); - - return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->key)); } - else - { - // TODO FEATURE: fallback to fragmentation, in case the message is too long - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n")); - goto except; + else{ + // multipart message } + } + return GNUNET_OK; except: - for (i = 0; i < used_elements; i++) + for (i = 0; i < session->used; i++) if (session->a[i]) gcry_mpi_release (session->a[i]); gcry_sexp_release (session->remote_pubkey); session->remote_pubkey = NULL; - GNUNET_free_non_null (session->a); + GNUNET_free (session->a); session->a = NULL; free_session (session); // and notify our client-session that we could not complete the session - if (responder_session) - // we just found the responder session in this queue - responder_session->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, - responder_session); + if (session->response) + // we just found the responder session in this queue + session->response->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_end_notification, + session->response); return GNUNET_SYSERR; } +/** + * Handle a multipart chunk of a response we got from another service we wanted to calculate a scalarproduct with. + * + * @param cls closure (set from #GNUNET_MESH_connect) + * @param tunnel connection to the other end + * @param tunnel_ctx place to store local state associated with the tunnel + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) + */ +static int +handle_service_response_multipart (void *cls, + struct GNUNET_MESH_Tunnel * tunnel, + void **tunnel_ctx, + const struct GNUNET_MessageHeader * message) +{ + struct ServiceSession * session; + const struct GNUNET_SCALARPRODUCT_multipart_message * msg = (const struct GNUNET_SCALARPRODUCT_multipart_message *) message; + unsigned char * current; + size_t read; + size_t i; + uint32_t contained=0; + size_t msg_size; + int rc; + + GNUNET_assert (NULL != message); + // are we in the correct state? + session = (struct ServiceSession *) * tunnel_ctx; + if ((ALICE != session->role) || (WAITING_FOR_MULTIPART_TRANSMISSION != session->state)) { + GNUNET_break_op (0); + return GNUNET_OK; + } + // shorter than minimum? + if (ntohs (msg->header.size) <= sizeof (struct GNUNET_SCALARPRODUCT_multipart_message)) { + goto invalid_msg; + } + contained = ntohl (msg->multipart_element_count); + msg_size = sizeof (struct GNUNET_SCALARPRODUCT_multipart_message) + + 2 * contained * PAILLIER_ELEMENT_LENGTH; + //sanity check: is the message as long as the message_count fields suggests? + if ((ntohs (msg->header.size) != msg_size) || (session->used < contained)) { + goto invalid_msg; + } + current = (unsigned char *) &msg[1]; + // Convert each k[][perm] to its MPI_value + for (i = 0; i < contained; i++) { + if (0 != (rc = gcry_mpi_scan (&session->r[i], GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { + LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); + GNUNET_break_op (0); + goto invalid_msg; + } + current += PAILLIER_ELEMENT_LENGTH; + if (0 != (rc = gcry_mpi_scan (&session->r_prime[i], GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { + LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); + GNUNET_break_op (0); + goto invalid_msg; + } + current += PAILLIER_ELEMENT_LENGTH; + } + session->transferred += contained; + if (session->transferred != session->used) + return GNUNET_OK; + session->state = SERVICE_RESPONSE_RECEIVED; + session->product = compute_scalar_product (session); + return GNUNET_SYSERR; // terminate the tunnel right away, we are done here! + +invalid_msg: + GNUNET_break_op (0); + gcry_mpi_release (session->s); + gcry_mpi_release (session->s_prime); + for (i = 0; session->r && i < session->used; i++){ + if (session->r[i]) gcry_mpi_release (session->r[i]); + if (session->r_prime[i]) gcry_mpi_release (session->r_prime[i]); + } + GNUNET_free_non_null (session->r); + GNUNET_free_non_null (session->r_prime); + session->s = NULL; + session->s_prime = NULL; + session->r = NULL; + session->r_prime = NULL; + session->tunnel = NULL; + // send message with product to client + session->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_response, + session); + // the tunnel has done its job, terminate our connection and the tunnel + // the peer will be notified that the tunnel was destroyed via tunnel_destruction_handler + // just close the connection, as recommended by Christian + return GNUNET_SYSERR; +} /** * Handle a response we got from another service we wanted to calculate a scalarproduct with. @@ -1912,112 +2274,92 @@ handle_service_response (void *cls, struct ServiceSession * session; const struct GNUNET_SCALARPRODUCT_service_response * msg = (const struct GNUNET_SCALARPRODUCT_service_response *) message; unsigned char * current; - uint32_t count; - gcry_mpi_t s = NULL; - gcry_mpi_t s_prime = NULL; size_t read; size_t i; - uint32_t used_element_count; + uint32_t contained=0; size_t msg_size; - gcry_mpi_t * r = NULL; - gcry_mpi_t * r_prime = NULL; int rc; GNUNET_assert (NULL != message); session = (struct ServiceSession *) * tunnel_ctx; - if (ALICE != session->role){ - GNUNET_break_op(0); - return GNUNET_SYSERR; + // are we in the correct state? + if (session->state != WAITING_FOR_SERVICE_REQUEST) { + goto invalid_msg; } - - count = session->used_element_count; - session->product = NULL; - session->state = SERVICE_RESPONSE_RECEIVED; - - //we need at least a peer and one message id to compare - if (sizeof (struct GNUNET_SCALARPRODUCT_service_response) > ntohs (msg->header.size)) - { - GNUNET_break_op (0); - goto invalid_msg; - } - used_element_count = ntohl (msg->used_element_count); + //we need at least a full message without elements attached + if (sizeof (struct GNUNET_SCALARPRODUCT_service_response) + 2 * PAILLIER_ELEMENT_LENGTH > ntohs (msg->header.size)) { + goto invalid_msg; + } + contained = ntohl (msg->contained_element_count); msg_size = sizeof (struct GNUNET_SCALARPRODUCT_service_response) - + 2 * used_element_count * PAILLIER_ELEMENT_LENGTH + + 2 * contained * PAILLIER_ELEMENT_LENGTH + 2 * PAILLIER_ELEMENT_LENGTH; //sanity check: is the message as long as the message_count fields suggests? - if ((ntohs (msg->header.size) != msg_size) || (count != used_element_count)) - { - GNUNET_break_op (0); - goto invalid_msg; - } - + if ((ntohs (msg->header.size) != msg_size) || (session->used < contained)) { + goto invalid_msg; + } + session->state = WAITING_FOR_MULTIPART_TRANSMISSION; + session->transferred = contained; //convert s current = (unsigned char *) &msg[1]; - if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG, current, - PAILLIER_ELEMENT_LENGTH, &read))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); - GNUNET_break_op (0); - goto invalid_msg; - } + if (0 != (rc = gcry_mpi_scan (&session->s, GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { + LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); + goto invalid_msg; + } current += PAILLIER_ELEMENT_LENGTH; //convert stick - if (0 != (rc = gcry_mpi_scan (&s_prime, GCRYMPI_FMT_USG, current, - PAILLIER_ELEMENT_LENGTH, &read))) - { + if (0 != (rc = gcry_mpi_scan (&session->s_prime, GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { + LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); + goto invalid_msg; + } + current += PAILLIER_ELEMENT_LENGTH; + session->r = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used); + session->r_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used); + // Convert each k[][perm] to its MPI_value + for (i = 0; i < contained; i++) { + if (0 != (rc = gcry_mpi_scan (&session->r[i], GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); - GNUNET_break_op (0); goto invalid_msg; } - current += PAILLIER_ELEMENT_LENGTH; - - r = GNUNET_malloc (sizeof (gcry_mpi_t) * count); - // Convert each kp[] to its MPI_value - for (i = 0; i < count; i++) - { - if (0 != (rc = gcry_mpi_scan (&r[i], GCRYMPI_FMT_USG, current, - PAILLIER_ELEMENT_LENGTH, &read))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); - GNUNET_break_op (0); - goto invalid_msg; - } - current += PAILLIER_ELEMENT_LENGTH; - } - - - r_prime = GNUNET_malloc (sizeof (gcry_mpi_t) * count); - // Convert each kq[] to its MPI_value - for (i = 0; i < count; i++) - { - if (0 != (rc = gcry_mpi_scan (&r_prime[i], GCRYMPI_FMT_USG, current, - PAILLIER_ELEMENT_LENGTH, &read))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); - GNUNET_break_op (0); - goto invalid_msg; - } - current += PAILLIER_ELEMENT_LENGTH; + current += PAILLIER_ELEMENT_LENGTH; + if (0 != (rc = gcry_mpi_scan (&session->r_prime[i], GCRYMPI_FMT_USG, current, + PAILLIER_ELEMENT_LENGTH, &read))) { + LOG_GCRY (GNUNET_ERROR_TYPE_DEBUG, "gcry_mpi_scan", rc); + goto invalid_msg; } - session->product = compute_scalar_product (session, r, r_prime, s, s_prime); + current += PAILLIER_ELEMENT_LENGTH; + } + if (session->transferred != session->used) + return GNUNET_OK; //wait for the other multipart chunks + session->state = SERVICE_RESPONSE_RECEIVED; + session->product = compute_scalar_product (session); + return GNUNET_SYSERR; // terminate the tunnel right away, we are done here! + invalid_msg: - if (s) - gcry_mpi_release (s); - if (s_prime) - gcry_mpi_release (s_prime); - for (i = 0; r && i < count; i++) - if (r[i]) gcry_mpi_release (r[i]); - for (i = 0; r_prime && i < count; i++) - if (r_prime[i]) gcry_mpi_release (r_prime[i]); - GNUNET_free_non_null (r); - GNUNET_free_non_null (r_prime); - + GNUNET_break_op (0); + if (session->s) + gcry_mpi_release (session->s); + if (session->s_prime) + gcry_mpi_release (session->s_prime); + for (i = 0; session->r && i < session->used; i++){ + if (session->r[i]) gcry_mpi_release (session->r[i]); + if (session->r_prime[i]) gcry_mpi_release (session->r_prime[i]); + } + GNUNET_free_non_null (session->r); + GNUNET_free_non_null (session->r_prime); + session->s = NULL; + session->s_prime = NULL; + session->r = NULL; + session->r_prime = NULL; session->tunnel = NULL; // send message with product to client - session->client_notification_task = - GNUNET_SCHEDULER_add_now (&prepare_client_response, - session); + session->client_notification_task = + GNUNET_SCHEDULER_add_now (&prepare_client_response, + session); // the tunnel has done its job, terminate our connection and the tunnel // the peer will be notified that the tunnel was destroyed via tunnel_destruction_handler // just close the connection, as recommended by Christian @@ -2040,30 +2382,35 @@ shutdown_task (void *cls, do_shutdown = GNUNET_YES; // terminate all owned open tunnels. - for (session = from_client_head; NULL != session; session = session->next) - { - if (FINALIZED != session->state) + for (session = from_client_head; NULL != session; session = session->next) { + if ((FINALIZED != session->state) && (NULL != session->tunnel)) { GNUNET_MESH_tunnel_destroy (session->tunnel); - if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) - { + session->tunnel = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != session->client_notification_task) { GNUNET_SCHEDULER_cancel (session->client_notification_task); session->client_notification_task = GNUNET_SCHEDULER_NO_TASK; } - if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task) - { + if (GNUNET_SCHEDULER_NO_TASK != session->service_request_task) { GNUNET_SCHEDULER_cancel (session->service_request_task); session->service_request_task = GNUNET_SCHEDULER_NO_TASK; } + if (NULL != session->client) { + GNUNET_SERVER_client_disconnect (session->client); + session->client = NULL; + } } for (session = from_service_head; NULL != session; session = session->next) - - if (my_mesh) - { - GNUNET_MESH_disconnect (my_mesh); - my_mesh = NULL; + if (NULL != session->tunnel) { + GNUNET_MESH_tunnel_destroy (session->tunnel); + session->tunnel = NULL; } -} + if (my_mesh) { + GNUNET_MESH_disconnect (my_mesh); + my_mesh = NULL; + } +} /** * Initialization of the program and message handlers @@ -2084,7 +2431,9 @@ run (void *cls, }; static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = { { &handle_service_request, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB, 0}, + { &handle_service_request_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ALICE_TO_BOB_MULTIPART, 0}, { &handle_service_response, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE, 0}, + { &handle_service_response_multipart, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_BOB_TO_ALICE_MULTIPART, 0}, {NULL, 0, 0} }; static const uint32_t ports[] = { @@ -2100,25 +2449,23 @@ run (void *cls, &handle_client_disconnect, NULL); GNUNET_break (GNUNET_OK == - GNUNET_CRYPTO_get_host_identity (c, - &me)); + GNUNET_CRYPTO_get_peer_identity (c, + &me)); my_mesh = GNUNET_MESH_connect (c, NULL, &tunnel_incoming_handler, &tunnel_destruction_handler, mesh_handlers, ports); - if (!my_mesh) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to MESH failed\n")); - GNUNET_SCHEDULER_shutdown (); - return; - } + if (!my_mesh) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to MESH failed\n")); + GNUNET_SCHEDULER_shutdown (); + return; + } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Mesh initialized\n")); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); } - /** * The main function for the scalarproduct service. *