+/**
+ * Cancel a request for notification.
+ *
+ * @param th handle from the original request.
+ */
+void
+GNUNET_CLIENT_notify_transmit_ready_cancel (struct
+ GNUNET_CLIENT_TransmitHandle *th)
+{
+ if (th->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_break (NULL == th->th);
+ GNUNET_SCHEDULER_cancel (th->reconnect_task);
+ th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ else
+ {
+ GNUNET_assert (NULL != th->th);
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
+ }
+ th->sock->th = NULL;
+ GNUNET_free (th);
+}
+
+
+/**
+ * Function called to notify a client about the socket
+ * begin ready to queue the message. "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure of type "struct TransmitGetResponseContext*"
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_for_response (void *cls, size_t size, void *buf)
+{
+ struct TransmitGetResponseContext *tc = cls;
+ uint16_t msize;
+
+ tc->sock->tag = NULL;
+ msize = ntohs (tc->hdr->size);
+ if (NULL == buf)
+ {
+#if DEBUG_CLIENT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Could not submit request, not expecting to receive a response.\n"));
+#endif
+ tc->rn (tc->rn_cls, NULL);
+ GNUNET_free (tc);
+ return 0;
+ }
+ GNUNET_assert (size >= msize);
+ memcpy (buf, tc->hdr, msize);
+ GNUNET_CLIENT_receive (tc->sock,
+ tc->rn,
+ tc->rn_cls,
+ GNUNET_TIME_absolute_get_remaining (tc->timeout));
+ GNUNET_free (tc);
+ return msize;
+}
+
+
+/**
+ * Convenience API that combines sending a request
+ * to the service and waiting for a response.
+ * If either operation times out, the callback
+ * will be called with a "NULL" response (in which
+ * case the connection should probably be destroyed).
+ *
+ * @param sock connection to use
+ * @param hdr message to transmit
+ * @param timeout when to give up (for both transmission
+ * and for waiting for a response)
+ * @param auto_retry if the connection to the service dies, should we
+ * automatically re-connect and retry (within the timeout period)
+ * or should we immediately fail in this case? Pass GNUNET_YES
+ * if the caller does not care about temporary connection errors,
+ * for example because the protocol is stateless
+ * @param rn function to call with the response
+ * @param rn_cls closure for rn
+ * @return GNUNET_OK on success, GNUNET_SYSERR if a request
+ * is already pending
+ */
+int
+GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection
+ *sock,
+ const struct GNUNET_MessageHeader
+ *hdr,
+ struct GNUNET_TIME_Relative timeout,
+ int auto_retry,
+ GNUNET_CLIENT_MessageHandler rn,
+ void *rn_cls)
+{
+ struct TransmitGetResponseContext *tc;
+ uint16_t msize;
+
+ if (NULL != sock->th)
+ return GNUNET_SYSERR;
+ GNUNET_assert (sock->tag == NULL);
+ msize = ntohs (hdr->size);
+ tc = GNUNET_malloc (sizeof (struct TransmitGetResponseContext) + msize);
+ tc->sock = sock;
+ tc->hdr = (const struct GNUNET_MessageHeader *) &tc[1];
+ memcpy (&tc[1], hdr, msize);
+ tc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ tc->rn = rn;
+ tc->rn_cls = rn_cls;
+ if (NULL == GNUNET_CLIENT_notify_transmit_ready (sock,
+ msize,
+ timeout,
+ auto_retry,
+ &transmit_for_response,
+ tc))
+ {
+ GNUNET_break (0);
+ GNUNET_free (tc);
+ return GNUNET_SYSERR;
+ }
+ sock->tag = tc;
+ return GNUNET_OK;
+}
+
+
+