+/**
+ * Free the given client request.
+ *
+ * @param cls the client request to free
+ * @param tc task context
+ */
+static void
+client_request_destroy (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ClientRequest *cr = cls;
+ struct GSF_LocalClient *lc;
+
+ cr->kill_task = GNUNET_SCHEDULER_NO_TASK;
+ lc = cr->lc;
+ GNUNET_CONTAINER_DLL_remove (lc->cr_head, lc->cr_tail, cr);
+ GSF_pending_request_cancel_ (cr->pr, GNUNET_NO);
+ GNUNET_STATISTICS_update (GSF_stats,
+ gettext_noop ("# client searches active"), -1,
+ GNUNET_NO);
+ GNUNET_free (cr);
+}
+
+
+/**
+ * Handle a reply to a pending request. Also called if a request
+ * expires (then with data == NULL). The handler may be called
+ * many times (depending on the request type), but will not be
+ * called during or after a call to GSF_pending_request_cancel
+ * and will also not be called anymore after a call signalling
+ * expiration.
+ *
+ * @param cls user-specified closure
+ * @param eval evaluation of the result
+ * @param pr handle to the original pending request
+ * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
+ * @param expiration when does 'data' expire?
+ * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
+ * @param type type of the block
+ * @param data response data, NULL on request expiration
+ * @param data_len number of bytes in data
+ */
+static void
+client_response_handler (void *cls, enum GNUNET_BLOCK_EvaluationResult eval,
+ struct GSF_PendingRequest *pr,
+ uint32_t reply_anonymity_level,
+ struct GNUNET_TIME_Absolute expiration,
+ struct GNUNET_TIME_Absolute last_transmission,
+ enum GNUNET_BLOCK_Type type, const void *data,
+ size_t data_len)
+{
+ struct ClientRequest *cr = cls;
+ struct GSF_LocalClient *lc;
+ struct ClientPutMessage *pm;
+ const struct GSF_PendingRequestData *prd;
+ size_t msize;
+
+ if (NULL == data)
+ {
+ /* ugh, request 'timed out' -- how can this be? */
+ GNUNET_break (0);
+ return;
+ }
+ prd = GSF_pending_request_get_data_ (pr);
+ GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
+ if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_STATISTICS_update (GSF_stats,
+ gettext_noop
+ ("# replies received for local clients"), 1,
+ GNUNET_NO);
+ GNUNET_assert (pr == cr->pr);
+ lc = cr->lc;
+ msize = sizeof (struct ClientPutMessage) + data_len;
+ {
+ char buf[msize];
+
+ pm = (struct ClientPutMessage *) buf;
+ pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT);
+ pm->header.size = htons (msize);
+ pm->type = htonl (type);
+ pm->expiration = GNUNET_TIME_absolute_hton (expiration);
+ pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
+ memcpy (&pm[1], data, data_len);
+ GSF_local_client_transmit_ (lc, &pm->header);
+ }
+#if DEBUG_FS_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Queued reply to query `%s' for local client\n",
+ GNUNET_h2s (&prd->query), (unsigned int) prd->type);
+#endif
+ if (eval != GNUNET_BLOCK_EVALUATION_OK_LAST)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != cr->kill_task)
+ cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy, cr);
+}
+
+