#include "gnunet_server_lib.h"
#include "arm.h"
-/**
- * How often do we re-try tranmsitting requests to ARM before
- * giving up? Note that if we succeeded transmitting a request
- * but failed to read a response, we do NOT re-try (since that
- * might result in ARM getting a request twice).
- */
-#define MAX_ATTEMPTS 4
-
-/**
- * Minimum delay between attempts to talk to ARM.
- */
-#define MIN_RETRY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
-
/**
* How long are we willing to wait for a service operation during the multi-operation
*/
void *cls;
- /**
- * The service that is being manipulated. Do not free.
- */
- const char *service_name;
-
/**
* Timeout for the operation.
*/
struct GNUNET_TIME_Absolute timeout;
- /**
- * Length of service_name plus one.
- */
- size_t slen;
-
- /**
- * Number of attempts left for transmitting the request to ARM.
- * We may fail the first time (say because ARM is not yet up),
- * in which case we wait a bit and re-try (timeout permitting).
- */
- unsigned int attempts_left;
-
/**
* Type of the request expressed as a message type (start or stop).
*/
}
-/**
- * We've failed to transmit the request to the ARM service.
- * Report our failure and clean up the state.
- *
- * @param sctx the state of the (now failed) request
- */
-static void
-report_transmit_failure (struct RequestContext *sctx)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Error while trying to transmit to ARM service\n"));
- if (sctx->callback != NULL)
- sctx->callback (sctx->cls, GNUNET_SYSERR);
- GNUNET_free (sctx);
-}
-
-
-/**
- * Transmit a request for a service status change to the
- * ARM service.
- *
- * @param cls the "struct RequestContext" identifying the request
- * @param size how many bytes are available in buf
- * @param buf where to write the request, NULL on error
- * @return number of bytes written to buf
- */
-static size_t
-send_service_msg (void *cls, size_t size, void *buf);
-
-
-/**
- * We've failed to transmit the request to the ARM service but
- * are now going to try again.
- *
- * @param cls state of the request
- * @param tc task context (unused)
- */
-static void
-retry_request (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct RequestContext *sctx = cls;
-
- if (NULL ==
- GNUNET_CLIENT_notify_transmit_ready (sctx->h->client,
- sctx->slen +
- sizeof (struct
- GNUNET_MessageHeader),
- GNUNET_TIME_absolute_get_remaining (sctx->timeout),
- &send_service_msg,
- sctx))
- {
- report_transmit_failure (sctx);
- return;
- }
-}
-
-
-/**
- * Transmit a request for a service status change to the
- * ARM service.
- *
- * @param cls the "struct RequestContext" identifying the request
- * @param size how many bytes are available in buf
- * @param buf where to write the request, NULL on error
- * @return number of bytes written to buf
- */
-static size_t
-send_service_msg (void *cls, size_t size, void *buf)
-{
- struct RequestContext *sctx = cls;
- struct GNUNET_MessageHeader *msg;
- struct GNUNET_TIME_Relative rem;
-
- if (buf == NULL)
- {
- GNUNET_CLIENT_disconnect (sctx->h->client);
- sctx->h->client = GNUNET_CLIENT_connect (sctx->h->sched,
- "arm",
- sctx->h->cfg);
- GNUNET_assert (sctx->h->client != NULL);
- rem = GNUNET_TIME_absolute_get_remaining (sctx->timeout);
- if ( (sctx->attempts_left-- > 0) &&
- (rem.value > 0) )
- {
- GNUNET_SCHEDULER_add_delayed (sctx->h->sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_KEEP,
- GNUNET_SCHEDULER_NO_TASK,
- GNUNET_TIME_relative_min (MIN_RETRY_DELAY,
- rem),
- &retry_request,
- sctx);
- return 0;
- }
- report_transmit_failure (sctx);
- return 0;
- }
-#if DEBUG_ARM
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Transmitting service request to ARM.\n"));
-#endif
- GNUNET_assert (size >= sctx->slen);
- msg = buf;
- msg->size = htons (sizeof (struct GNUNET_MessageHeader) + sctx->slen);
- msg->type = htons (sctx->type);
- memcpy (&msg[1], sctx->service_name, sctx->slen);
- GNUNET_CLIENT_receive (sctx->h->client,
- &handle_response,
- sctx,
- GNUNET_TIME_absolute_get_remaining (sctx->timeout));
- return sctx->slen + sizeof (struct GNUNET_MessageHeader);
-}
-
-
/**
* Start or stop a service.
*
{
struct RequestContext *sctx;
size_t slen;
+ struct GNUNET_MessageHeader *msg;
slen = strlen (service_name) + 1;
if (slen + sizeof (struct GNUNET_MessageHeader) >
sctx->h = h;
sctx->callback = cb;
sctx->cls = cb_cls;
- sctx->service_name = (const char*) &sctx[1];
- memcpy (&sctx[1],
- service_name,
- slen);
sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- sctx->slen = slen;
- sctx->attempts_left = MAX_ATTEMPTS;
sctx->type = type;
- retry_request (sctx, NULL);
+ msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen);
+ msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
+ msg->type = htons (sctx->type);
+ memcpy (&msg[1], service_name, slen);
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (sctx->h->client,
+ msg,
+ GNUNET_TIME_absolute_get_remaining (sctx->timeout),
+ GNUNET_YES,
+ &handle_response,
+ sctx))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Error while trying to transmit to ARM service\n"));
+ if (cb != NULL)
+ cb (cb_cls, GNUNET_SYSERR);
+ GNUNET_free (sctx);
+ GNUNET_free (msg);
+ return;
+ }
+ GNUNET_free (msg);
}
#!/bin/sh
exe="./gnunet-arm -c test_arm_api_data.conf"
-out=`mktemp /tmp/test-gnunetd-arm-logXXXXXXXX`
+out=`mktemp /tmp/test-gnunet-arm-logXXXXXXXX`
#DEBUG="-L DEBUG"
/**
* Handle for our current transmission request.
*/
- struct GNUNET_CONNECTION_TransmitHandle *th;
+ struct GNUNET_CLIENT_TransmitHandle *th;
/**
* Head of doubly-linked list of pending requests.
sizeof (struct InitMessage) +
sizeof (uint16_t) * h->hcnt,
GNUNET_TIME_UNIT_SECONDS,
+ GNUNET_NO,
&transmit_start, h);
}
h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
th->msize,
GNUNET_TIME_absolute_get_remaining
- (th->timeout), &request_start,
+ (th->timeout),
+ GNUNET_NO,
+ &request_start,
h);
}
GNUNET_CLIENT_notify_transmit_ready (h->client,
sizeof (struct InitMessage) +
sizeof (uint16_t) * h->hcnt, timeout,
+ GNUNET_YES,
&transmit_start, h);
}
GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
{
if (handle->th != NULL)
- GNUNET_CONNECTION_notify_transmit_ready_cancel (handle->th);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (handle->sched, handle->reconnect_task);
GNUNET_CLIENT_disconnect (handle->client);
libgnunetdatastore_la_SOURCES = \
datastore_api.c datastore.h plugin_datastore.h
libgnunetdatastore_la_LIBADD = \
+ $(top_builddir)/src/arm/libgnunetarm.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
libgnunetdatastore_la_LDFLAGS = \
* @author Christian Grothoff
*/
#include "platform.h"
+#include "gnunet_arm_service.h"
#include "gnunet_datastore_service.h"
#include "datastore.h"
};
+
/**
* Connect to the datastore service.
*
c = GNUNET_CLIENT_connect (sched, "datastore", cfg);
if (c == NULL)
return NULL; /* oops */
+ GNUNET_ARM_start_services (cfg, sched, "datastore", NULL);
h = GNUNET_malloc (sizeof(struct GNUNET_DATASTORE_Handle) +
GNUNET_SERVER_MAX_MESSAGE_SIZE);
h->client = c;
GNUNET_CLIENT_notify_transmit_ready (h->client,
sizeof(struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_MINUTES,
+ GNUNET_YES,
&transmit_drop,
h))
return;
}
if (h->client != NULL)
GNUNET_CLIENT_disconnect (h->client);
+ GNUNET_ARM_stop_services (h->cfg, h->sched, "datastore", NULL);
GNUNET_free (h);
}
}
-/**
- * Transmit message to datastore service and then
- * read a status message.
- *
- * @param cls closure with handle to datastore
- * @param size number of bytes we can transmit at most
- * @param buf where to write transmission, NULL on
- * timeout
- * @return number of bytes copied to buf
- */
-static size_t
-transmit_get_status (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_DATASTORE_Handle *h = cls;
- GNUNET_DATASTORE_ContinuationWithStatus cont = h->response_proc;
- uint16_t msize;
-
- if (buf == NULL)
- {
- h->message_size = 0;
- h->response_proc = NULL;
- cont (h->response_proc_cls,
- GNUNET_SYSERR,
- _("Error transmitting message to datastore service."));
- return 0;
- }
- msize = h->message_size;
- GNUNET_assert (msize <= size);
- memcpy (buf, &h[1], msize);
-#if DEBUG_DATASTORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitted %u byte message to datastore service, now waiting for status.\n",
- msize);
-#endif
- h->message_size = 0;
- GNUNET_CLIENT_receive (h->client,
- &with_status_response_handler,
- h,
- GNUNET_TIME_absolute_get_remaining (h->timeout));
- return msize;
-}
-
-
/**
* Helper function that will initiate the
* transmission of a message to the datastore
h->response_proc_cls = cont_cls;
h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
h->message_size = msize;
- if (NULL == GNUNET_CLIENT_notify_transmit_ready (h->client,
- msize,
- timeout,
- &transmit_get_status,
- h))
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (h->client,
+ hdr,
+ timeout,
+ GNUNET_YES,
+ &with_status_response_handler,
+ h))
{
GNUNET_break (0);
h->response_proc = NULL;
}
-/**
- * Transmit message to datastore service and then
- * read a result message.
- *
- * @param cls closure with handle to datastore
- * @param size number of bytes we can transmit at most
- * @param buf where to write transmission, NULL on
- * timeout
- * @return number of bytes copied to buf
- */
-static size_t
-transmit_get_result (void *cls,
- size_t size,
- void *buf)
-{
- struct GNUNET_DATASTORE_Handle *h = cls;
- GNUNET_DATASTORE_Iterator cont = h->response_proc;
- uint16_t msize;
-
- if (buf == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Error transmitting message to datastore service.\n"));
- h->response_proc = NULL;
- h->message_size = 0;
- cont (h->response_proc_cls,
- NULL, 0, NULL, 0, 0, 0,
- GNUNET_TIME_UNIT_ZERO_ABS, 0);
- return 0;
- }
- msize = h->message_size;
- GNUNET_assert (msize <= size);
- memcpy (buf, &h[1], msize);
-#if DEBUG_DATASTORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Transmitted %u byte message to datastore service, now waiting for result.\n",
- msize);
-#endif
- h->message_size = 0;
- GNUNET_CLIENT_receive (h->client,
- &with_result_response_handler,
- h,
- GNUNET_TIME_absolute_get_remaining (h->timeout));
- return msize;
-}
-
-
-
/**
* Function called to trigger obtaining the next result
* from the datastore.
/**
- * Helper function that will initiate the
- * transmission of a message to the datastore
- * service. The message must already be prepared
- * and stored in the buffer at the end of the
- * handle. The message must be of a type that
- * expects a "DataMessage" in response.
+ * Helper function that will initiate the transmission of a message to
+ * the datastore service. The message must already be prepared and
+ * stored in the buffer at the end of the handle. The message must be
+ * of a type that expects a "DataMessage" in response.
*
* @param h handle to the service with prepared message
* @param cont function to call with result
h->response_proc_cls = cont_cls;
h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
h->message_size = msize;
- if (NULL == GNUNET_CLIENT_notify_transmit_ready (h->client,
- msize,
- timeout,
- &transmit_get_result,
- h))
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (h->client,
+ hdr,
+ timeout,
+ GNUNET_YES,
+ &with_result_response_handler,
+ h))
{
GNUNET_break (0);
h->response_proc = NULL;
struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_END
};
- pid = GNUNET_OS_start_process ("gnunet-service-datastore",
- "gnunet-service-datastore",
+ pid = GNUNET_OS_start_process ("gnunet-service-arm",
+ "gnunet-service-arm",
#if VERBOSE
"-L", "DEBUG",
#endif
struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_END
};
- pid = GNUNET_OS_start_process ("gnunet-service-datastore",
- "gnunet-service-datastore",
+ pid = GNUNET_OS_start_process ("gnunet-service-arm",
+ "gnunet-service-arm",
#if VERBOSE
"-L", "DEBUG",
#endif
[PATHS]
SERVICEHOME = /tmp/test-gnunetd-datastore/
+DEFAULTCONFIG = test_datastore_api_data.conf
+
+[arm]
+DEFAULTSERVICES = resolver
+PORT = 42466
+HOSTNAME = localhost
+
+[resolver]
+PORT = 42464
+HOSTNAME = localhost
[datastore]
PORT = 22654
# REJECT_FROM =
# REJECT_FROM6 =
# PREFIX =
+
+[statistics]
+PORT = 22667
+HOSTNAME = localhost
+
+[testing]
+WEAKRANDOM = YES
struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_END
};
- pid = GNUNET_OS_start_process ("gnunet-service-datastore",
- "gnunet-service-datastore",
+ pid = GNUNET_OS_start_process ("gnunet-service-arm",
+ "gnunet-service-arm",
#if VERBOSE
"-L", "DEBUG",
#endif
* Non-NULL if we are currently having a request for
* transmission pending with the client handle.
*/
- struct GNUNET_CONNECTION_TransmitHandle *th;
+ struct GNUNET_CLIENT_TransmitHandle *th;
/**
* Identity of the peer having the content, or all-zeros
dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
sizeof (struct SearchMessage),
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_NO,
&transmit_download_request,
dc);
/* abort all pending requests */
if (NULL != dc->th)
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (dc->th);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th);
dc->th = NULL;
}
GNUNET_CLIENT_disconnect (dc->client);
/* abort all pending requests */
if (NULL != dc->th)
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (dc->th);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th);
dc->th = NULL;
}
GNUNET_CLIENT_disconnect (dc->client);
dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
sizeof (struct SearchMessage),
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_NO,
&transmit_download_request,
dc);
return msize;
dc->th = GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct SearchMessage),
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_NO,
&transmit_download_request,
dc);
GNUNET_CLIENT_receive (client,
{
if (NULL != dc->th)
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (dc->th);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th);
dc->th = NULL;
}
GNUNET_CONTAINER_multihashmap_iterate (dc->active,
dc->task);
if (NULL != dc->th)
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (dc->th);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (dc->th);
dc->th = NULL;
}
if (NULL != dc->client)
}
-/**
- * Transmit the request to get a list of all
- * indexed files to the "FS" service.
- *
- * @param cls closure (of type "struct GetIndexedContext*")
- * @param size number of bytes availabe in buf
- * @param buf where to write the message, NULL on error
- * @return number of bytes written to buf
- */
-static size_t
-transmit_get_indexed (void *cls,
- size_t size,
- void *buf)
-{
- struct GetIndexedContext *gic = cls;
- struct GNUNET_MessageHeader *hdr;
-
- if (NULL == buf)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to transmit `%s' request to `%s' service.\n"),
- "GET_INDEXED",
- "fs");
- GNUNET_SCHEDULER_add_continuation (gic->h->sched,
- GNUNET_NO,
- gic->cont,
- gic->cont_cls,
- GNUNET_SCHEDULER_REASON_TIMEOUT);
- GNUNET_CLIENT_disconnect (gic->client);
- GNUNET_free (gic);
- return 0;
- }
- GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
- hdr = buf;
- hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
- hdr->type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET);
- GNUNET_CLIENT_receive (gic->client,
- &handle_index_info,
- gic,
- GNUNET_CONSTANTS_SERVICE_TIMEOUT);
- return sizeof (struct GNUNET_MessageHeader);
-}
-
-
/**
* Iterate over all indexed files.
*
{
struct GNUNET_CLIENT_Connection *client;
struct GetIndexedContext *gic;
+ struct GNUNET_MessageHeader msg;
client = GNUNET_CLIENT_connect (h->sched,
"fs",
gic->iterator_cls = iterator_cls;
gic->cont = cont;
gic->cont_cls = cont_cls;
- GNUNET_CLIENT_notify_transmit_ready (client,
- sizeof (struct GNUNET_MessageHeader),
- GNUNET_CONSTANTS_SERVICE_TIMEOUT,
- &transmit_get_indexed,
- gic);
+ msg.size = htons (sizeof (struct GNUNET_MessageHeader));
+ msg.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CLIENT_transmit_and_get_response (client,
+ &msg,
+ GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_YES,
+ &handle_index_info,
+ gic));
}
/* end of fs_list_indexed.c */
GNUNET_CLIENT_transmit_and_get_response (client,
&ism->header,
GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES,
&process_index_start_response,
sc);
GNUNET_free (ism);
GNUNET_CLIENT_notify_transmit_ready (client,
size,
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_NO,
&transmit_search_request,
sc);
}
GNUNET_CLIENT_notify_transmit_ready (client,
size,
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_NO,
&transmit_search_request,
sc);
return sc;
GNUNET_CLIENT_transmit_and_get_response (uc->client,
&req.header,
GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ GNUNET_YES,
&process_fs_response,
uc);
}
struct GNUNET_TIME_Relative timeout);
+/**
+ * Transmit handle for client connections.
+ */
+struct GNUNET_CLIENT_TransmitHandle;
+
+
/**
* Ask the client to call us once the specified number of bytes
* are free in the transmission buffer. May call the notify
* @param size number of bytes to send
* @param timeout after how long should we give up (and call
* notify with buf NULL and size 0)?
+ * @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 notify function to call
* @param notify_cls closure for notify
* @return NULL if someone else is already waiting to be notified
* non-NULL if the notify callback was queued (can be used to cancel
* using GNUNET_CONNECTION_notify_transmit_ready_cancel)
*/
-struct GNUNET_CONNECTION_TransmitHandle
+struct GNUNET_CLIENT_TransmitHandle
*GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock,
size_t size,
struct GNUNET_TIME_Relative timeout,
+ int auto_retry,
GNUNET_CONNECTION_TransmitReadyNotify
- notify, void *notify_cls);
+ notify,
+ void *notify_cls);
+/**
+ * Cancel a request for notification.
+ *
+ * @param th handle from the original request.
+ */
+void
+GNUNET_CLIENT_notify_transmit_ready_cancel (struct GNUNET_CLIENT_TransmitHandle *th);
+
/**
* Convenience API that combines sending a request
* @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
*/
-void
+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);
cc->msg = &pam->header;
GNUNET_CLIENT_notify_transmit_ready (client,
ntohs (pam->header.size),
- ADD_PEER_TIMEOUT, ©_and_free, cc);
+ ADD_PEER_TIMEOUT,
+ GNUNET_YES,
+ ©_and_free, cc);
}
}
-static size_t
-copy_then_receive (void *cls, size_t size, void *buf)
-{
- struct InfoContext *ic = cls;
- const struct GNUNET_MessageHeader *msg =
- (const struct GNUNET_MessageHeader *) &ic[1];
- uint16_t msize;
-
- if (buf == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _
- ("Failed to transmit message of type %u to `%s' service.\n"),
- ntohs (msg->type), "peerinfo");
- ic->callback (ic->callback_cls, NULL, NULL, 1);
- GNUNET_CLIENT_disconnect (ic->client);
- GNUNET_free (ic);
- return 0;
- }
- msize = ntohs (msg->size);
- GNUNET_assert (size >= msize);
- memcpy (buf, msg, msize);
- GNUNET_CLIENT_receive (ic->client,
- &info_handler,
- ic,
- GNUNET_TIME_absolute_get_remaining (ic->timeout));
- return msize;
-}
-
-
/**
* Call a method for each known matching host and change
* its trust value. The method will be invoked once for
lpm->trust_change = htonl (trust_delta);
memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
}
- GNUNET_CLIENT_notify_transmit_ready (client,
- hs, timeout, ©_then_receive, ihc);
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (client,
+ (const struct GNUNET_MessageHeader*) &ihc[1],
+ timeout,
+ GNUNET_YES,
+ &info_handler,
+ ihc))
+ {
+ GNUNET_break (0);
+ ihc->callback (ihc->callback_cls, NULL, NULL, 1);
+ GNUNET_CLIENT_disconnect (ihc->client);
+ GNUNET_free (ihc);
+ return;
+ }
}
/* end of peerinfo_api.c */
if (NULL ==
GNUNET_CLIENT_notify_transmit_ready (h->client,
h->current->msize,
- timeout, &transmit_action, h))
+ timeout,
+ GNUNET_YES,
+ &transmit_action, h))
{
#if DEBUG_STATISTICS
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
/**
* Handle to our registration with the client for notification.
*/
- struct GNUNET_CONNECTION_TransmitHandle *network_handle;
+ struct GNUNET_CLIENT_TransmitHandle *network_handle;
/**
* Linked list of transmit handles that are waiting for the
th->notify_size,
GNUNET_TIME_absolute_get_remaining
(th->timeout),
+ GNUNET_NO,
&transport_notify_ready,
h);
GNUNET_assert (NULL != h->network_handle);
#endif
if (h->network_handle != NULL)
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (h->network_handle);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->network_handle);
h->network_handle = NULL;
h->transmission_scheduled = GNUNET_NO;
th = h->connect_ready_head;
h = th->handle;
if ((h->connect_ready_head == NULL) && (h->network_handle != NULL))
{
- GNUNET_CONNECTION_notify_transmit_ready_cancel (h->network_handle);
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->network_handle);
h->network_handle = NULL;
h->transmission_scheduled = GNUNET_NO;
}
#define DEBUG_CLIENT GNUNET_NO
+
+/**
+ * How often do we re-try tranmsitting requests before giving up?
+ * Note that if we succeeded transmitting a request but failed to read
+ * a response, we do NOT re-try.
+ */
+#define MAX_ATTEMPTS 10
+
/**
* Struct to refer to a GNUnet TCP connection.
* This is more than just a socket because if the server
*/
struct GNUNET_SCHEDULER_Handle *sched;
+ /**
+ * Our configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
/**
* Name of the service we interact with.
*/
};
-/**
- * Get a connection with a service.
- *
- * @param sched scheduler to use
- * @param service_name name of the service
- * @param cfg configuration to use
- * @return NULL on error (service unknown to configuration)
- */
-struct GNUNET_CLIENT_Connection *
-GNUNET_CLIENT_connect (struct GNUNET_SCHEDULER_Handle *sched,
- const char *service_name,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+static struct GNUNET_CONNECTION_Handle *
+do_connect (struct GNUNET_SCHEDULER_Handle *sched,
+ const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- struct GNUNET_CLIENT_Connection *ret;
struct GNUNET_CONNECTION_Handle *sock;
char *hostname;
unsigned long long port;
port,
GNUNET_SERVER_MAX_MESSAGE_SIZE);
GNUNET_free (hostname);
+ return sock;
+}
+
+
+/**
+ * Get a connection with a service.
+ *
+ * @param sched scheduler to use
+ * @param service_name name of the service
+ * @param cfg configuration to use
+ * @return NULL on error (service unknown to configuration)
+ */
+struct GNUNET_CLIENT_Connection *
+GNUNET_CLIENT_connect (struct GNUNET_SCHEDULER_Handle *sched,
+ const char *service_name,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_CLIENT_Connection *ret;
+ struct GNUNET_CONNECTION_Handle *sock;
+
+ sock = do_connect (sched, service_name, cfg);
if (sock == NULL)
return NULL;
ret = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection));
ret->sock = sock;
ret->sched = sched;
ret->service_name = GNUNET_strdup (service_name);
+ ret->cfg = cfg;
return ret;
}
}
+/**
+ * Handle for a transmission request.
+ */
+struct GNUNET_CLIENT_TransmitHandle
+{
+ /**
+ * Connection state.
+ */
+ struct GNUNET_CLIENT_Connection *sock;
+
+ /**
+ * Function to call to get the data for transmission.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ /**
+ * Closure for notify.
+ */
+ void *notify_cls;
+
+ /**
+ * Handle to the transmission with the underlying
+ * connection.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *th;
+
+ /**
+ * Timeout.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * If we are re-trying and are delaying to do so,
+ * handle to the scheduled task managing the delay.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+ /**
+ * Number of bytes requested.
+ */
+ size_t size;
+
+ /**
+ * Are we allowed to re-try to connect without telling
+ * the user (of this API) about the connection troubles?
+ */
+ int auto_retry;
+
+ /**
+ * Number of attempts left for transmitting the request. We may
+ * fail the first time (say because the service is not yet up), in
+ * which case (if auto_retry is set) we wait a bit and re-try
+ * (timeout permitting).
+ */
+ unsigned int attempts_left;
+
+};
+
+
+
+/**
+ * Connection notifies us about failure or success of
+ * a transmission request. Either pass it on to our
+ * user or, if possible, retry.
+ *
+ * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
+ * @param size number of bytes available for transmission
+ * @param buf where to write them
+ * @return number of bytes written to buf
+ */
+static size_t
+client_notify (void *cls,
+ size_t size,
+ void *buf);
+
+
+
+/**
+ * This task is run if we should re-try connection to the
+ * service after a while.
+ *
+ * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request
+ * @param tc unused
+ */
+static void
+client_delayed_retry (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_CLIENT_TransmitHandle *th = cls;
+
+ th->task = GNUNET_SCHEDULER_NO_TASK;
+ th->sock->sock = do_connect (th->sock->sched,
+ th->sock->service_name,
+ th->sock->cfg);
+ th->th = GNUNET_CONNECTION_notify_transmit_ready (th->sock->sock,
+ th->size,
+ GNUNET_TIME_absolute_get_remaining (th->timeout),
+ &client_notify,
+ th);
+ if (th->th == NULL)
+ {
+ GNUNET_break (0);
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_free (th);
+ return;
+ }
+}
+
+
+/**
+ * Connection notifies us about failure or success of
+ * a transmission request. Either pass it on to our
+ * user or, if possible, retry.
+ *
+ * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
+ * @param size number of bytes available for transmission
+ * @param buf where to write them
+ * @return number of bytes written to buf
+ */
+static size_t
+client_notify (void *cls,
+ size_t size,
+ void *buf)
+{
+ struct GNUNET_CLIENT_TransmitHandle *th = cls;
+ size_t ret;
+ struct GNUNET_TIME_Relative delay;
+
+ if (buf == NULL)
+ {
+ delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
+ delay.value /= 2;
+ if ( (GNUNET_YES != th->auto_retry) ||
+ (0 == --th->attempts_left) ||
+ (delay.value < 1) )
+ {
+ GNUNET_break (0 == th->notify (th->notify_cls,
+ 0,
+ NULL));
+ GNUNET_free (th);
+ return 0;
+ }
+ /* auto-retry */
+ GNUNET_CONNECTION_destroy (th->sock->sock);
+ th->sock->sock = NULL;
+ th->th = NULL;
+ delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_UNIT_SECONDS);
+ th->task = GNUNET_SCHEDULER_add_delayed (th->sock->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ delay,
+ &client_delayed_retry,
+ th);
+ return 0;
+ }
+ GNUNET_assert (size >= th->size);
+ ret = th->notify (th->notify_cls,
+ size,
+ buf);
+ GNUNET_free (th);
+ return ret;
+}
+
+
/**
* Ask the client to call us once the specified number of bytes
* are free in the transmission buffer. May call the notify
* @param size number of bytes to send
* @param timeout after how long should we give up (and call
* notify with buf NULL and size 0)?
+ * @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 notify function to call
* @param notify_cls closure for notify
* @return NULL if our buffer will never hold size bytes,
* a handle if the notify callback was queued (can be used to cancel)
*/
-struct GNUNET_CONNECTION_TransmitHandle *
+struct GNUNET_CLIENT_TransmitHandle *
GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock,
size_t size,
struct GNUNET_TIME_Relative timeout,
+ int auto_retry,
GNUNET_CONNECTION_TransmitReadyNotify
notify, void *notify_cls)
{
- return GNUNET_CONNECTION_notify_transmit_ready (sock->sock,
- size,
- timeout, notify, notify_cls);
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle));
+ th->sock = sock;
+ th->size = size;
+ th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ th->auto_retry = auto_retry;
+ th->notify = notify;
+ th->notify_cls = notify_cls;
+ th->attempts_left = MAX_ATTEMPTS;
+ th->th = GNUNET_CONNECTION_notify_transmit_ready (sock->sock,
+ size,
+ timeout,
+ &client_notify,
+ th);
+ if (NULL == th->th)
+ {
+ GNUNET_free (th);
+ return NULL;
+ }
+ return th;
+}
+
+
+/**
+ * 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->task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (th->sock->sched,
+ th->task);
+ else
+ {
+ GNUNET_break (NULL != th->th);
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
+ }
+ GNUNET_free (th);
}
* @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
*/
-void
+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)
{
tc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
tc->rn = rn;
tc->rn_cls = rn_cls;
- GNUNET_CLIENT_notify_transmit_ready (sock,
- msize,
- timeout,
- &transmit_for_response,
- tc);
+ if (NULL == GNUNET_CLIENT_notify_transmit_ready (sock,
+ msize,
+ timeout,
+ auto_retry,
+ &transmit_for_response,
+ tc))
+ {
+ GNUNET_free (tc);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
}
*/
void *cls;
- /**
- * FIXME.
- */
- struct GNUNET_RESOLVER_GetMessage *msg;
-
/**
* FIXME.
*/
}
-/**
- * FIXME
- *
- * @param cls FIXME
- * @param size number of bytes available in buf
- * @param buf target buffer, NULL on error
- * @return number of bytes written to buf
- */
-static size_t
-transmit_get_ip (void *cls, size_t size, void *buf)
-{
- struct GetAddressContext *actx = cls;
- uint16_t ms;
-
- if (buf == NULL)
- {
- /* timeout / error */
- GNUNET_free (actx->msg);
- actx->callback (actx->cls, NULL, 0);
- GNUNET_CLIENT_disconnect (actx->client);
- GNUNET_free (actx);
- return 0;
- }
- ms = ntohs (actx->msg->header.size);
- GNUNET_assert (size >= ms);
- memcpy (buf, actx->msg, ms);
- GNUNET_free (actx->msg);
- actx->msg = NULL;
- GNUNET_CLIENT_receive (actx->client,
- &handle_address_response,
- actx,
- GNUNET_TIME_absolute_get_remaining (actx->timeout));
- return ms;
-}
-
-
-
/**
* Convert a string to one or more IP addresses.
*
actx->cls = callback_cls;
actx->client = client;
actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- actx->msg = msg;
#if DEBUG_RESOLVER
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Resolver requests DNS resolution of hostname `%s'.\n"),
hostname);
#endif
- if (NULL ==
- GNUNET_CLIENT_notify_transmit_ready (client,
- slen +
- sizeof (struct
- GNUNET_RESOLVER_GetMessage),
- timeout, &transmit_get_ip, actx))
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (client,
+ &msg->header,
+ timeout,
+ GNUNET_YES,
+ &handle_address_response,
+ actx))
{
GNUNET_free (msg);
GNUNET_free (actx);
GNUNET_CLIENT_disconnect (client);
return;
}
+ GNUNET_free (msg);
}
*/
void *cls;
- /**
- * FIXME.
- */
- struct GNUNET_RESOLVER_GetMessage *msg;
-
/**
* FIXME.
*/
}
-/**
- * FIXME
- *
- * @param cls FIXME
- * @param size number of bytes available in buf
- * @param buf target buffer, NULL on error
- * @return number of bytes written to buf
- */
-static size_t
-transmit_get_hostname (void *cls, size_t size, void *buf)
-{
- struct GetHostnameContext *hctx = cls;
- uint16_t msize;
-
- if (buf == NULL)
- {
- GNUNET_free (hctx->msg);
- hctx->callback (hctx->cls, NULL);
- GNUNET_CLIENT_disconnect (hctx->client);
- GNUNET_free (hctx);
- return 0;
- }
- msize = ntohs (hctx->msg->header.size);
- GNUNET_assert (size >= msize);
- memcpy (buf, hctx->msg, msize);
- GNUNET_free (hctx->msg);
- hctx->msg = NULL;
- GNUNET_CLIENT_receive (hctx->client,
- &handle_hostname_response,
- hctx,
- GNUNET_TIME_absolute_get_remaining (hctx->timeout));
- return msize;
-}
-
-
-
-
/**
* Get an IP address as a string.
*
hctx->cls = cls;
hctx->client = client;
hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- hctx->msg = msg;
- if (NULL ==
- GNUNET_CLIENT_notify_transmit_ready (client,
- sizeof (struct
- GNUNET_RESOLVER_GetMessage)
- + salen, timeout,
- &transmit_get_hostname, hctx))
+ if (GNUNET_OK !=
+ GNUNET_CLIENT_transmit_and_get_response (client,
+ &msg->header,
+ timeout,
+ GNUNET_YES,
+ &handle_hostname_response,
+ hctx))
{
GNUNET_free (msg);
callback (cls, NULL);
GNUNET_CLIENT_disconnect (client);
GNUNET_free (hctx);
}
+ GNUNET_free (msg);
}
/**
GNUNET_assert (NULL !=
GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct
- GNUNET_MessageHeader),
+ GNUNET_MessageHeader),
GNUNET_TIME_UNIT_SECONDS,
+ GNUNET_NO,
&make_msg, NULL));
GNUNET_CLIENT_receive (client, &recv_bounce, cls,
GNUNET_TIME_relative_multiply
256,
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_MILLISECONDS, 250),
+ GNUNET_NO,
¬ify_ready, NULL);
}
256,
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_MILLISECONDS, 250),
+ GNUNET_NO,
¬ify_ready, NULL);
}
GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_SECONDS,
+ GNUNET_NO,
&build_msg, client);
}
GNUNET_CLIENT_notify_transmit_ready (client,
sizeof (struct GNUNET_MessageHeader),
GNUNET_TIME_UNIT_SECONDS,
+ GNUNET_NO,
&build_msg, client);
}