+
+/**
+ * Process a get response monitor message from the service.
+ *
+ * @param cls The DHT handle.
+ * @param msg monitor get response message from the service
+ */
+static void
+handle_monitor_get_resp (void *cls,
+ const struct GNUNET_DHT_MonitorGetRespMessage *msg)
+{
+ struct GNUNET_DHT_Handle *handle = cls;
+ size_t msize = ntohs (msg->header.size) - sizeof (*msg);
+ const struct GNUNET_PeerIdentity *path;
+ uint32_t getl = ntohl (msg->get_path_length);
+ uint32_t putl = ntohl (msg->put_path_length);
+ struct GNUNET_DHT_MonitorHandle *mh;
+
+ path = (const struct GNUNET_PeerIdentity *) &msg[1];
+ for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
+ {
+ if (NULL == mh->get_resp_cb)
+ continue;
+ if ( ( (GNUNET_BLOCK_TYPE_ANY == mh->type) ||
+ (mh->type == ntohl(msg->type)) ) &&
+ ( (NULL == mh->key) ||
+ (0 == memcmp (mh->key,
+ &msg->key,
+ sizeof (struct GNUNET_HashCode))) ) )
+ mh->get_resp_cb (mh->cb_cls,
+ (enum GNUNET_BLOCK_Type) ntohl (msg->type),
+ path,
+ getl,
+ &path[getl],
+ putl,
+ GNUNET_TIME_absolute_ntoh(msg->expiration_time),
+ &msg->key,
+ (const void *) &path[getl + putl],
+ msize - sizeof (struct GNUNET_PeerIdentity) * (putl + getl));
+ }
+}
+
+
+/**
+ * Check validity of a put monitor message from the service.
+ *
+ * @param cls The DHT handle.
+ * @param msg Monitor put message from the service.
+ * @return #GNUNET_OK if everything went fine,
+ * #GNUNET_SYSERR if the message is malformed.
+ */
+static int
+check_monitor_put (void *cls,
+ const struct GNUNET_DHT_MonitorPutMessage *msg)
+{
+ size_t msize;
+ uint32_t putl;
+
+ msize = ntohs (msg->header.size) - sizeof (*msg);
+ putl = ntohl (msg->put_path_length);
+ if ((msize / sizeof (struct GNUNET_PeerIdentity)) < putl)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Process a put monitor message from the service.
+ *
+ * @param cls The DHT handle.
+ * @param msg Monitor put message from the service.
+ */
+static void
+handle_monitor_put (void *cls,
+ const struct GNUNET_DHT_MonitorPutMessage *msg)
+{
+ struct GNUNET_DHT_Handle *handle = cls;
+ size_t msize = ntohs (msg->header.size) - sizeof (*msg);
+ uint32_t putl = ntohl (msg->put_path_length);
+ const struct GNUNET_PeerIdentity *path;
+ struct GNUNET_DHT_MonitorHandle *mh;
+
+ path = (const struct GNUNET_PeerIdentity *) &msg[1];
+ for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
+ {
+ if (NULL == mh->put_cb)
+ continue;
+ if ( ( (GNUNET_BLOCK_TYPE_ANY == mh->type) ||
+ (mh->type == ntohl(msg->type)) ) &&
+ ( (NULL == mh->key) ||
+ (0 == memcmp (mh->key,
+ &msg->key,
+ sizeof (struct GNUNET_HashCode))) ) )
+ mh->put_cb (mh->cb_cls,
+ ntohl (msg->options),
+ (enum GNUNET_BLOCK_Type) ntohl(msg->type),
+ ntohl (msg->hop_count),
+ ntohl (msg->desired_replication_level),
+ putl,
+ path,
+ GNUNET_TIME_absolute_ntoh(msg->expiration_time),
+ &msg->key,
+ (const void *) &path[putl],
+ msize - sizeof (struct GNUNET_PeerIdentity) * putl);
+ }
+}
+
+
+/**
+ * Verify that client result message received from the service is well-formed.
+ *
+ * @param cls The DHT handle.
+ * @param msg Monitor put message from the service.
+ * @return #GNUNET_OK if everything went fine,
+ * #GNUNET_SYSERR if the message is malformed.
+ */
+static int
+check_client_result (void *cls,
+ const struct GNUNET_DHT_ClientResultMessage *msg)
+{
+ size_t msize = ntohs (msg->header.size) - sizeof (*msg);
+ uint32_t put_path_length = ntohl (msg->put_path_length);
+ uint32_t get_path_length = ntohl (msg->get_path_length);
+ size_t meta_length;
+
+ meta_length =
+ sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length);
+ if ( (msize < meta_length) ||
+ (get_path_length >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
+ (put_path_length >
+ GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Process a given reply that might match the given request.
+ *
+ * @param cls the `struct GNUNET_DHT_ClientResultMessage`
+ * @param key query of the request
+ * @param value the `struct GNUNET_DHT_GetHandle` of a request matching the same key
+ * @return #GNUNET_YES to continue to iterate over all results
+ */
+static int
+process_client_result (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ const struct GNUNET_DHT_ClientResultMessage *crm = cls;
+ struct GNUNET_DHT_GetHandle *get_handle = value;
+ size_t msize = ntohs (crm->header.size) - sizeof (*crm);
+ uint32_t put_path_length = ntohl (crm->put_path_length);
+ uint32_t get_path_length = ntohl (crm->get_path_length);
+ const struct GNUNET_PeerIdentity *put_path;
+ const struct GNUNET_PeerIdentity *get_path;
+ struct GNUNET_HashCode hc;
+ size_t data_length;
+ size_t meta_length;
+ const void *data;
+
+ if (crm->unique_id != get_handle->unique_id)
+ {
+ /* UID mismatch */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring reply for %s: UID mismatch: %llu/%llu\n",
+ GNUNET_h2s (key),
+ crm->unique_id,
+ get_handle->unique_id);
+ return GNUNET_YES;
+ }
+ /* FIXME: might want to check that type matches */
+ meta_length =
+ sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length);
+ data_length = msize - meta_length;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Giving %u byte reply for %s to application\n",
+ (unsigned int) data_length,
+ GNUNET_h2s (key));
+ put_path = (const struct GNUNET_PeerIdentity *) &crm[1];
+ get_path = &put_path[put_path_length];
+ data = &get_path[get_path_length];
+ /* remember that we've seen this result */
+ GNUNET_CRYPTO_hash (data,
+ data_length,
+ &hc);
+ if (get_handle->seen_results_size == get_handle->seen_results_end)
+ GNUNET_array_grow (get_handle->seen_results,
+ get_handle->seen_results_size,
+ get_handle->seen_results_size * 2 + 1);
+ get_handle->seen_results[get_handle->seen_results_end++] = hc;
+ /* no need to block it explicitly, service already knows about it! */
+ get_handle->iter (get_handle->iter_cls,
+ GNUNET_TIME_absolute_ntoh (crm->expiration),
+ key,
+ get_path,
+ get_path_length,
+ put_path,
+ put_path_length,
+ ntohl (crm->type),
+ data_length,
+ data);