aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2013-03-13 17:49:26 +0000
committerLRN <lrn1986@gmail.com>2013-03-13 17:49:26 +0000
commit405f776bc08486af4edb80e18149c0829732b347 (patch)
treed5fc635a51641dec6b53cb2540276f34ae8f6210
parent3ceae682287492ecc768aea5c4c463216a35774d (diff)
All-encompassing ARM update
-rw-r--r--src/arm/Makefile.am2
-rw-r--r--src/arm/arm.h53
-rw-r--r--src/arm/arm_api.c1130
-rw-r--r--src/arm/gnunet-arm.c521
-rw-r--r--src/arm/gnunet-service-arm.c526
-rw-r--r--src/arm/mockup-service.c14
-rw-r--r--src/arm/test_arm_api.c151
-rw-r--r--src/arm/test_exponential_backoff.c265
-rw-r--r--src/arm/test_gnunet_service_arm.c81
-rw-r--r--src/include/gnunet_arm_service.h295
-rw-r--r--src/include/gnunet_protocols.h13
-rw-r--r--src/include/gnunet_server_lib.h37
-rw-r--r--src/regex/gnunet-regex-profiler.c147
-rw-r--r--src/regex/regex_test_lib.c2
-rw-r--r--src/util/client.c1
-rw-r--r--src/util/connection.c8
-rw-r--r--src/util/server.c78
17 files changed, 2069 insertions, 1255 deletions
diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am
index 48d9955b8e..dcc0f125f3 100644
--- a/src/arm/Makefile.am
+++ b/src/arm/Makefile.am
@@ -19,7 +19,7 @@ endif
lib_LTLIBRARIES = libgnunetarm.la
libgnunetarm_la_SOURCES = \
- arm_api.c arm.h
+ arm_api.c arm_monitor_api.c arm.h
libgnunetarm_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL) $(XLIB)
diff --git a/src/arm/arm.h b/src/arm/arm.h
index 21884107c5..aad16fd71c 100644
--- a/src/arm/arm.h
+++ b/src/arm/arm.h
@@ -36,20 +36,60 @@
GNUNET_NETWORK_STRUCT_BEGIN
/**
- * Reply from ARM to client.
+ * Status update from ARM to client.
*/
-struct GNUNET_ARM_ResultMessage
+struct GNUNET_ARM_StatusMessage
{
/**
- * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT.
+ * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_STATUS.
*/
struct GNUNET_MessageHeader header;
/**
- * Status from the 'enum GNUNET_ARM_ProcessStatus'
+ * Status from the 'enum GNUNET_ARM_ServiceStatus'
*/
uint32_t status;
+
+ /* followed by a 0-terminated service name */
+};
+
+struct GNUNET_ARM_Message
+{
+ /**
+ * Reply to client, type is GNUNET_MESSAGE_TYPE_ARM_RESULT or
+ * GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT.
+ * OR
+ * Request from client, type is GNUNET_MESSAGE_TYPE_ARM_REQUEST
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of a request that is being replied to.
+ * OR
+ * ID of a request that is being sent.
+ */
+ uint64_t request_id;
+
+ /* For requests - followed by a 0-terminated service name */
+};
+
+
+/**
+ * Reply from ARM to client.
+ */
+struct GNUNET_ARM_ResultMessage
+{
+
+ /**
+ * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT, with an ID.
+ */
+ struct GNUNET_ARM_Message arm_msg;
+
+ /**
+ * Result from the 'enum GNUNET_ARM_Result'
+ */
+ uint32_t result;
};
/**
@@ -61,9 +101,10 @@ struct GNUNET_ARM_ResultMessage
struct GNUNET_ARM_ListResultMessage
{
/**
- * Reply to client is of type GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT
+ * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT,
+ * with an ID.
*/
- struct GNUNET_MessageHeader header;
+ struct GNUNET_ARM_Message arm_msg;
/**
* Number of '\0' terminated strings that follow
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
index aee9afb249..d434ff3af2 100644
--- a/src/arm/arm_api.c
+++ b/src/arm/arm_api.c
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors)
+ (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
@@ -21,7 +21,7 @@
/**
* @file arm/arm_api.c
* @brief API for accessing the ARM service
- * @author Christian Grothoff
+ * @author Christian Grothoff, LRN
*/
#include "platform.h"
#include "gnunet_arm_service.h"
@@ -38,7 +38,7 @@ struct GNUNET_ARM_Handle
{
/**
- * Our connection to the ARM service.
+ * Our control connection to the ARM service.
*/
struct GNUNET_CLIENT_Connection *client;
@@ -47,257 +47,469 @@ struct GNUNET_ARM_Handle
*/
struct GNUNET_CONFIGURATION_Handle *cfg;
+ /**
+ * Handle for our current transmission request.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *cth;
+
+ /**
+ * Head of doubly-linked list of pending requests.
+ */
+ struct ARMControlMessage *control_pending_head;
+
+ /**
+ * Tail of doubly-linked list of pending requests.
+ */
+ struct ARMControlMessage *control_pending_tail;
+
+ /**
+ * Head of doubly-linked list of sent requests.
+ */
+ struct ARMControlMessage *control_sent_head;
+
+ /**
+ * Tail of doubly-linked list of sent requests.
+ */
+ struct ARMControlMessage *control_sent_tail;
+
+ /**
+ * ID of the reconnect task (if any).
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ /**
+ * Current delay we use for re-trying to connect to core.
+ */
+ struct GNUNET_TIME_Relative retry_backoff;
+
+ /**
+ * Are we currently disconnected and hence unable to send?
+ */
+ unsigned char currently_down;
+
+ /**
+ * Callback to invoke on connection/disconnection.
+ */
+ GNUNET_ARM_ConnectionStatusCallback conn_status;
+
+ /**
+ * Closure for conn_status.
+ */
+ void *conn_status_cls;
+
+ /**
+ * GNUNET_YES if we're running a service test.
+ */
+ unsigned char service_test_is_active;
+
+ /**
+ * Counter for request identifiers
+ */
+ uint64_t request_id_counter;
};
+
/**
- * Context for handling the shutdown of a service.
+ * Entry in a doubly-linked list of control messages to be transmitted
+ * to the arm service.
+ *
+ * The actual message is allocated at the end of this struct.
*/
-struct ShutdownContext
+struct ARMControlMessage
{
/**
- * Connection to the service that is being shutdown.
+ * This is a doubly-linked list.
*/
- struct GNUNET_CLIENT_Connection *sock;
+ struct ARMControlMessage *next;
/**
- * Time allowed for shutdown to happen.
+ * This is a doubly-linked list.
*/
- struct GNUNET_TIME_Absolute timeout;
+ struct ARMControlMessage *prev;
/**
- * Task set up to cancel the shutdown request on timeout.
+ * Callback for service state change requests.
*/
- GNUNET_SCHEDULER_TaskIdentifier cancel_task;
+ GNUNET_ARM_ResultCallback result_cont;
/**
- * Task to call once shutdown complete
+ * Callback for service list requests.
*/
- GNUNET_CLIENT_ShutdownTask cont;
+ GNUNET_ARM_ServiceListCallback list_cont;
/**
- * Closure for shutdown continuation
+ * Closure for 'result_cont' or 'list_cont'.
*/
void *cont_cls;
/**
- * Handle for transmission request.
+ * Timeout for the operation.
*/
- struct GNUNET_CLIENT_TransmitHandle *th;
+ struct GNUNET_TIME_Absolute timeout;
+ /**
+ * Type of the request expressed as a message type (start, stop or list).
+ */
+ uint16_t type;
+
+ /**
+ * Flags for passing std descriptors to ARM (when starting ARM).
+ */
+ enum GNUNET_OS_InheritStdioFlags std_inheritance;
+
+ /**
+ * ARM handle.
+ */
+ struct GNUNET_ARM_Handle *h;
+
+ /**
+ * Message to send.
+ */
+ struct GNUNET_ARM_Message *msg;
+
+ /**
+ * Task to run when request times out.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task_id;
};
+static void
+client_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg);
+
+static void
+reconnect_arm (struct GNUNET_ARM_Handle *h);
+
+static void
+trigger_next_request (struct GNUNET_ARM_Handle *h, int ignore_currently_down);
+
/**
- * Handler receiving response to service shutdown requests.
- * First call with NULL: service misbehaving, or something.
- * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK:
- * - service will shutdown
- * Second call with NULL:
- * - service has now really shut down.
+ * Task scheduled to try to re-connect to arm.
*
- * @param cls closure
- * @param msg NULL, indicating socket closure.
+ * @param cls the 'struct GNUNET_ARM_Handle'
+ * @param tc task context
*/
static void
-service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+reconnect_arm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_ARM_Handle *h = cls;
+
+ h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to ARM service after delay\n");
+ reconnect_arm (h);
+}
+
+
+static void
+clear_pending_messages (struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus result)
{
- struct ShutdownContext *shutdown_ctx = cls;
+ struct ARMControlMessage *cm;
- if (NULL != msg)
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Clearing pending messages\n");
+
+ while (NULL != (cm = h->control_pending_head))
{
- /* We just expected a disconnect! Report the error and be done with it... */
- GNUNET_break (0);
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
- GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
- return;
+ GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
+ h->control_pending_tail, cm);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cm->timeout_task_id);
+ GNUNET_SCHEDULER_cancel (cm->timeout_task_id);
+ if (NULL != cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, result, NULL, 0);
+ GNUNET_free_non_null (cm->msg);
+ GNUNET_free (cm);
}
- if (NULL != shutdown_ctx->cont)
- /* shutdown is now complete, as we waited for the network disconnect... */
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_DOWN);
- GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
}
-
/**
- * Shutting down took too long, cancel receive and return error.
+ * Close down any existing connection to the ARM service and
+ * try re-establishing it later.
*
- * @param cls closure
- * @param tc context information (why was this task triggered now)
+ * @param h our handle
*/
static void
-service_shutdown_cancel (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+reconnect_arm_later (struct GNUNET_ARM_Handle *h)
{
- struct ShutdownContext *shutdown_ctx = cls;
+ if (GNUNET_NO != h->currently_down)
+ return;
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
-}
+ if (NULL != h->cth)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
+ h->cth = NULL;
+ }
+
+ if (NULL != h->client)
+ {
+ GNUNET_CLIENT_disconnect (h->client);
+ h->client = NULL;
+ }
+
+ if (NULL != h->conn_status)
+ h->conn_status (h->conn_status_cls, h, GNUNET_NO, GNUNET_NO);
+
+ h->currently_down = GNUNET_YES;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task);
+ h->reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_arm_task, h);
+ /* Don't clear pending messages on disconnection, deliver them later
+ clear_pending_messages (h, GNUNET_ARM_REQUEST_DISCONNECTED);
+ GNUNET_assert (NULL == h->control_pending_head);
+ */
+ h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
+}
/**
- * If possible, write a shutdown message to the target
- * buffer and destroy the client connection.
+ * Transmit the next message to the arm service.
*
- * @param cls the "struct GNUNET_CLIENT_Connection" to destroy
+ * @param cls closure with the 'struct GNUNET_ARM_Handle'
* @param size number of bytes available in buf
- * @param buf NULL on error, otherwise target buffer
- * @return number of bytes written to buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
*/
static size_t
-write_shutdown (void *cls, size_t size, void *buf)
+transmit_arm_message (void *cls, size_t size, void *buf)
{
- struct ShutdownContext *shutdown_ctx = cls;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_ARM_Handle *h = cls;
+ struct ARMControlMessage *cm;
+ struct GNUNET_ARM_Message *arm_msg;
+ uint16_t msize;
+ uint64_t request_id;
- shutdown_ctx->th = NULL;
- if (size < sizeof (struct GNUNET_MessageHeader))
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "transmit_arm_message is running with %p buffer of size %lu. ARM is known to be %s\n",
+ buf, size, h->currently_down ? "unconnected" : "connected");
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task);
+ h->cth = NULL;
+ if ((GNUNET_YES == h->currently_down) && (NULL != buf))
+ {
+ h->currently_down = GNUNET_NO;
+ if (NULL != h->conn_status)
+ h->conn_status (h->conn_status_cls, h, GNUNET_YES, GNUNET_NO);
+ h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+ GNUNET_CLIENT_receive (h->client, &client_notify_handler, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ if (NULL == buf)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission failed, initiating reconnect\n");
+ reconnect_arm_later (h);
+ return 0;
+ }
+ if (NULL == (cm = h->control_pending_head))
{
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _("Failed to transmit shutdown request to client.\n"));
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
- return 0; /* client disconnected */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue is empty, not sending anything\n");
+ return 0;
}
- GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
- shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
- shutdown_ctx->cancel_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
- (shutdown_ctx->timeout),
- &service_shutdown_cancel, shutdown_ctx);
- msg = (struct GNUNET_MessageHeader *) buf;
- msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
- msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- return sizeof (struct GNUNET_MessageHeader);
+
+ GNUNET_assert (NULL != cm->msg);
+ msize = ntohs (cm->msg->header.size);
+ if (size < msize)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Request is too big (%u < %u), not sending it\n", size, msize);
+ trigger_next_request (h, GNUNET_NO);
+ return 0;
+ }
+ arm_msg = cm->msg;
+ if (0 == h->request_id_counter)
+ h->request_id_counter++;
+ request_id = h->request_id_counter++;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting control message with %u bytes of type %u to arm with id %llu\n",
+ (unsigned int) msize, (unsigned int) ntohs (cm->msg->header.type), request_id);
+ arm_msg->request_id = GNUNET_htonll (request_id);
+ memcpy (buf, cm->msg, msize);
+ /* Otherwise we won't be able to find it later! */
+ arm_msg->request_id = request_id;
+
+ GNUNET_CONTAINER_DLL_remove (h->control_pending_head,
+ h->control_pending_tail, cm);
+ GNUNET_CONTAINER_DLL_insert_tail (h->control_sent_head,
+ h->control_sent_tail, cm);
+
+ /* Don't free msg, keep it around (kind of wasteful, but then we don't
+ * really have many messages to handle, and it'll be freed when it times
+ * out anyway.
+ */
+ trigger_next_request (h, GNUNET_NO);
+ return msize;
}
/**
- * Request that the service should shutdown.
- * Afterwards, the connection will automatically be
- * disconnected. Hence the "sock" should not
- * be used by the caller after this call
- * (calling this function frees "sock" after a while).
+ * Check the list of pending requests, send the next
+ * one to the arm.
*
- * @param sock the socket connected to the service
- * @param timeout how long to wait before giving up on transmission
- * @param cont continuation to call once the service is really down
- * @param cont_cls closure for continuation
+ * @param h arm handle
+ * @param ignore_currently_down transmit message even if not initialized?
+ */
+static void
+trigger_next_request (struct GNUNET_ARM_Handle *h, int ignore_currently_down)
+{
+ uint16_t msize;
+
+ if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "ARM connection down, not processing queue\n");
+ return;
+ }
+ if (NULL != h->cth)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Request pending, not processing queue\n");
+ return;
+ }
+ if (NULL != h->control_pending_head)
+ msize =
+ ntohs (((struct GNUNET_MessageHeader *) &h->
+ control_pending_head[1])->size);
+ else if (GNUNET_NO == ignore_currently_down)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Request queue empty, not processing queue\n");
+ return; /* no pending message */
+ }
+ h->cth =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, msize,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO, &transmit_arm_message, h);
+}
+
+
+/**
+ * Connect to arm.
*
+ * @param h arm handle
*/
static void
-arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_CLIENT_ShutdownTask cont, void *cont_cls)
+reconnect_arm (struct GNUNET_ARM_Handle *h)
{
- struct ShutdownContext *shutdown_ctx;
-
- shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
- shutdown_ctx->cont = cont;
- shutdown_ctx->cont_cls = cont_cls;
- shutdown_ctx->sock = sock;
- shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- shutdown_ctx->th = GNUNET_CLIENT_notify_transmit_ready (sock,
- sizeof (struct GNUNET_MessageHeader),
- timeout, GNUNET_NO, &write_shutdown,
- shutdown_ctx);
+ GNUNET_assert (NULL == h->client);
+ GNUNET_assert (GNUNET_YES == h->currently_down);
+ h->client = GNUNET_CLIENT_connect ("arm", h->cfg);
+ if (NULL == h->client)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "arm_api, GNUNET_CLIENT_connect returned NULL\n");
+ if (NULL != h->conn_status)
+ h->conn_status (h->conn_status_cls, h, GNUNET_NO, GNUNET_YES);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
+ trigger_next_request (h, GNUNET_YES);
}
/**
- * Setup a context for communicating with ARM. Note that this
+ * Set up a context for communicating with ARM. Note that this
* can be done even if the ARM service is not yet running.
+ * Never fails.
*
* @param cfg configuration to use (needed to contact ARM;
* the ARM service may internally use a different
* configuration to determine how to start the service).
- * @param service service that *this* process is implementing/providing, can be NULL
- * @return context to use for further ARM operations, NULL on error
+ * @return context to use for further ARM operations
*/
struct GNUNET_ARM_Handle *
-GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *service)
+GNUNET_ARM_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_ARM_Handle *ret;
ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle));
ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ ret->currently_down = GNUNET_YES;
+ ret->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
return ret;
}
/**
- * Disconnect from the ARM service.
+ * Start connecting to the ARM service using the context.
*
- * @param h the handle that was being used
+ * @param h ARM handle
+ * @param conn_status will be called when connecting/disconnecting
+ * @param cls closure for conn_status
*/
void
-GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
+GNUNET_ARM_connect (struct GNUNET_ARM_Handle *h,
+ GNUNET_ARM_ConnectionStatusCallback conn_status, void *cls)
{
- if (h->client != NULL)
- GNUNET_CLIENT_disconnect (h->client);
- GNUNET_CONFIGURATION_destroy (h->cfg);
- GNUNET_free (h);
+ h->conn_status = conn_status;
+ h->conn_status_cls = cls;
+ reconnect_arm (h);
}
-struct ARM_ShutdownContext
+/**
+ * Disconnect from the ARM service (if connected) and destroy the context.
+ * Don't call inside an ARM callback!
+ *
+ * @param h the handle that was being used
+ */
+void
+GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *handle)
{
- /**
- * Callback to call once shutdown complete.
- */
- GNUNET_ARM_Callback cb;
-
- /**
- * Closure for callback.
- */
- void *cb_cls;
-};
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from ARM service\n");
+ if (NULL != handle->cth)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth);
+ handle->cth = NULL;
+ }
+ clear_pending_messages (handle, GNUNET_ARM_REQUEST_DISCONNECTED);
+ if (NULL != handle->client)
+ {
+ GNUNET_CLIENT_disconnect (handle->client);
+ handle->client = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (handle->reconnect_task);
+ handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_NO == handle->service_test_is_active)
+ {
+ GNUNET_CONFIGURATION_destroy (handle->cfg);
+ GNUNET_free (handle);
+ }
+}
/**
- * Internal state for a request with ARM.
+ * Message timed out. Remove it from the queue.
+ *
+ * @param cls the message (struct ARMControlMessage *)
+ * @param tc task context
*/
-struct RequestContext
+static void
+control_message_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
+ struct ARMControlMessage *cm = cls;
+ struct GNUNET_ARM_Message *arm_msg;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Control message timed out\n");
+ arm_msg = cm->msg;
+ if ((NULL == arm_msg) || (0 == arm_msg->request_id))
+ {
+ GNUNET_CONTAINER_DLL_remove (cm->h->control_pending_head,
+ cm->h->control_pending_tail, cm);
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_remove (cm->h->control_sent_head,
+ cm->h->control_sent_tail, cm);
+ }
+ if (NULL != cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_TIMEOUT, NULL, 0);
+ else if (NULL != cm->list_cont)
+ cm->list_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_TIMEOUT, 0, NULL);
+ GNUNET_free_non_null (cm->msg);
+ GNUNET_free (cm);
+}
- /**
- * Pointer to our handle with ARM.
- */
- struct GNUNET_ARM_Handle *h;
-
- /**
- * Function to call with a status code for the requested operation.
- */
- GNUNET_ARM_Callback callback;
-
- /**
- * Closure for "callback".
- */
- void *cls;
-
- /**
- * Timeout for the operation.
- */
- struct GNUNET_TIME_Absolute timeout;
-
- /**
- * Type of the request expressed as a message type (start or stop).
- */
- uint16_t type;
-
- /**
- * Flags for passing std descriptors to ARM (when starting ARM).
- */
- enum GNUNET_OS_InheritStdioFlags std_inheritance;
-
-};
#include "do_start_process.c"
@@ -308,78 +520,89 @@ struct RequestContext
* or not ARM is running; if it is, report success. If
* it is not, start the ARM process.
*
- * @param cls the context for the request that we will report on (struct RequestContext*)
+ * @param cls the context for the request that we will report on (struct ARMControlMessage *)
* @param tc why were we called (reason says if ARM is running)
*/
static void
arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct RequestContext *pos = cls;
+ struct ARMControlMessage *cm = cls;
struct GNUNET_OS_Process *proc;
+ unsigned char test_is_active;
char *cbinary;
char *binary;
char *config;
char *loprefix;
char *lopostfix;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+ test_is_active = cm->h->service_test_is_active;
+
+ /* FIXME: shouldn't we check for GNUNET_SCHEDULER_REASON_SHUTDOWN ? */
+ if ((GNUNET_YES == test_is_active) &&
+ (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n",
"gnunet-service-arm");
/* arm is running! */
- if (pos->callback != NULL)
- pos->callback (pos->cls, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
- GNUNET_free (pos);
+ if (cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
+ }
+ if (GNUNET_NO == test_is_active)
+ {
+ /* User disconnected & destroyed ARM handle in the middle of
+ * the service test, so we kept the handle around until now.
+ */
+ GNUNET_CONFIGURATION_destroy (cm->h->cfg);
+ GNUNET_free (cm->h);
+ }
+ if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) ||
+ (GNUNET_NO == test_is_active))
+ {
+ GNUNET_free (cm);
return;
}
+ cm->h->service_test_is_active = GNUNET_NO;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Looks like `%s' is not running, will start it.\n",
"gnunet-service-arm");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX",
- &loprefix))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (
+ cm->h->cfg, "arm", "PREFIX", &loprefix))
loprefix = GNUNET_strdup ("");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS",
- &lopostfix))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (
+ cm->h->cfg, "arm", "OPTIONS", &lopostfix))
lopostfix = GNUNET_strdup ("");
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY",
- &cbinary))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (
+ cm->h->cfg, "arm", "BINARY", &cbinary))
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "arm", "BINARY");
- if (pos->callback != NULL)
- pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN);
- GNUNET_free (pos);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, "arm", "BINARY");
+ if (cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_NOT_KNOWN);
+ GNUNET_free (cm);
GNUNET_free (loprefix);
GNUNET_free (lopostfix);
return;
}
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG",
- &config))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (
+ cm->h->cfg, "arm", "CONFIG", &config))
config = NULL;
binary = GNUNET_OS_get_libexec_binary_path (cbinary);
GNUNET_free (cbinary);
- if ((GNUNET_YES ==
- GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM"))
- && (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING",
- "WEAKRANDOM"))
- && (GNUNET_NO ==
- GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING",
- "HOSTFILE")))
+ if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (
+ cm->h->cfg, "TESTING", "WEAKRANDOM")) &&
+ (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (
+ cm->h->cfg, "TESTING", "WEAKRANDOM")) &&
+ (GNUNET_NO == GNUNET_CONFIGURATION_have_value (
+ cm->h->cfg, "TESTING", "HOSTFILE")))
{
/* Means we are ONLY running locally */
/* we're clearly running a test, don't daemonize */
if (NULL == config)
- proc = do_start_process (GNUNET_NO, pos->std_inheritance,
+ proc = do_start_process (GNUNET_NO, cm->std_inheritance,
NULL, loprefix, binary,
/* no daemonization! */
lopostfix, NULL);
else
- proc = do_start_process (GNUNET_NO, pos->std_inheritance,
+ proc = do_start_process (GNUNET_NO, cm->std_inheritance,
NULL, loprefix, binary, "-c", config,
/* no daemonization! */
lopostfix, NULL);
@@ -387,11 +610,11 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
else
{
if (NULL == config)
- proc = do_start_process (GNUNET_NO, pos->std_inheritance,
+ proc = do_start_process (GNUNET_NO, cm->std_inheritance,
NULL, loprefix, binary,
"-d", lopostfix, NULL);
else
- proc = do_start_process (GNUNET_NO, pos->std_inheritance,
+ proc = do_start_process (GNUNET_NO, cm->std_inheritance,
NULL, loprefix, binary, "-c", config,
"-d", lopostfix, NULL);
}
@@ -401,52 +624,18 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
GNUNET_free (lopostfix);
if (NULL == proc)
{
- if (pos->callback != NULL)
- pos->callback (pos->cls, GNUNET_ARM_PROCESS_FAILURE);
- GNUNET_free (pos);
+ if (cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm",
+ GNUNET_ARM_RESULT_START_FAILED);
+ GNUNET_free (cm);
return;
}
- if (pos->callback != NULL)
- pos->callback (pos->cls, GNUNET_ARM_PROCESS_STARTING);
+ if (cm->result_cont)
+ cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm",
+ GNUNET_ARM_RESULT_STARTING);
GNUNET_OS_process_destroy (proc);
- GNUNET_free (pos);
-}
-
-
-/**
- * Process a response from ARM to a request for a change in service
- * status.
- *
- * @param cls the request context
- * @param msg the response
- */
-static void
-handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
-{
- struct RequestContext *sc = cls;
- const struct GNUNET_ARM_ResultMessage *res;
- enum GNUNET_ARM_ProcessStatus status;
-
- if ((msg == NULL) ||
- (ntohs (msg->size) != sizeof (struct GNUNET_ARM_ResultMessage)))
- {
- GNUNET_break (0);
- GNUNET_CLIENT_disconnect (sc->h->client);
- sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg);
- GNUNET_assert (NULL != sc->h->client);
- if (sc->callback != NULL)
- sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
- GNUNET_free (sc);
- return;
- }
- res = (const struct GNUNET_ARM_ResultMessage *) msg;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received response from ARM for service `%s': %u\n",
- (const char *) &sc[1], ntohs (msg->type));
- status = (enum GNUNET_ARM_ProcessStatus) ntohl (res->status);
- if (sc->callback != NULL)
- sc->callback (sc->cls, status);
- GNUNET_free (sc);
+ reconnect_arm (cm->h);
+ GNUNET_free (cm);
}
@@ -462,74 +651,65 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
*/
static void
change_service (struct GNUNET_ARM_Handle *h, const char *service_name,
- struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb,
+ struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cb,
void *cb_cls, uint16_t type)
{
- struct RequestContext *sctx;
+ struct ARMControlMessage *cm;
size_t slen;
- struct GNUNET_MessageHeader *msg;
+ struct GNUNET_ARM_Message *msg;
slen = strlen (service_name) + 1;
- if (slen + sizeof (struct GNUNET_MessageHeader) >=
+ if (slen + sizeof (struct GNUNET_ARM_Message) >=
GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
GNUNET_break (0);
if (cb != NULL)
- cb (cb_cls, GNUNET_NO);
+ cb (cb_cls, h, GNUNET_ARM_REQUEST_TOO_LONG, NULL, 0);
return;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- (type ==
- GNUNET_MESSAGE_TYPE_ARM_START) ?
- "Requesting start of service `%s'.\n" :
- "Requesting termination of service `%s'.\n", service_name);
- sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
- sctx->h = h;
- sctx->callback = cb;
- sctx->cls = cb_cls;
- sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- sctx->type = type;
- memcpy (&sctx[1], service_name, slen);
- msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen);
- msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
- msg->type = htons (sctx->type);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting %s of service `%s'.\n",
+ (GNUNET_MESSAGE_TYPE_ARM_START == type) ? "start" : "termination",
+ service_name);
+ cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen);
+ cm->h = h;
+ cm->result_cont = cb;
+ cm->cont_cls = cb_cls;
+ cm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ memcpy (&cm[1], service_name, slen);
+ msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message) + slen);
+ msg->header.size = htons (sizeof (struct GNUNET_ARM_Message) + slen);
+ msg->header.type = htons (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_break (0);
- if (cb != NULL)
- cb (cb_cls, GNUNET_SYSERR);
- GNUNET_free (sctx);
- GNUNET_free (msg);
- return;
- }
- GNUNET_free (msg);
+ cm->msg = msg;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Inserting a control message into the queue. Timeout is %llu\n",
+ GNUNET_TIME_absolute_get_remaining (cm->timeout).rel_value);
+ GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
+ h->control_pending_tail, cm);
+ cm->timeout_task_id =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (cm->timeout), &control_message_timeout, cm);
+ trigger_next_request (h, GNUNET_NO);
}
/**
- * Start a service.
+ * Request for a service to be started.
*
* @param h handle to ARM
* @param service_name name of the service
* @param std_inheritance inheritance of std streams
* @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
+ * @param cont callback to invoke after request is sent or not sent
+ * @param cont_cls closure for callback
*/
void
-GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
- const char *service_name,
- enum GNUNET_OS_InheritStdioFlags std_inheritance,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_Callback cb, void *cb_cls)
+GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h,
+ const char *service_name, enum GNUNET_OS_InheritStdioFlags std_inheritance,
+ struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cont,
+ void *cont_cls)
{
- struct RequestContext *sctx;
- struct GNUNET_CLIENT_Connection *client;
+ struct ARMControlMessage *cm;
size_t slen;
LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -537,258 +717,266 @@ GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO));
if (0 == strcasecmp ("arm", service_name))
{
- slen = strlen ("arm") + 1;
- sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
- sctx->h = h;
- sctx->callback = cb;
- sctx->cls = cb_cls;
- sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- sctx->std_inheritance = std_inheritance;
- memcpy (&sctx[1], service_name, slen);
- GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report,
- sctx);
- return;
- }
- if (NULL == h->client)
- {
- client = GNUNET_CLIENT_connect ("arm", h->cfg);
- if (client == NULL)
+ /* Possible cases:
+ * 1) We're connected to ARM already. Invoke the callback immediately.
+ * 2) We're not connected to ARM.
+ * Cancel any reconnection attempts temporarily, then perform
+ * a service test.
+ */
+ if (GNUNET_NO == h->currently_down)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "ARM is already running\n");
+ if (NULL != cont)
+ cont (cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
+ }
+ else if (GNUNET_NO == h->service_test_is_active)
{
+ if (NULL != h->cth)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
+ h->cth = NULL;
+ }
+ if (NULL != h->client)
+ {
+ GNUNET_CLIENT_disconnect (h->client);
+ h->client = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (h->reconnect_task);
+ h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "arm_api, GNUNET_CLIENT_connect returned NULL\n");
- cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR);
- return;
+ "Not connected to ARM, will do a service test\n");
+
+ slen = strlen ("arm") + 1;
+ cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen);
+ cm->h = h;
+ cm->result_cont = cont;
+ cm->cont_cls = cont_cls;
+ cm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ cm->std_inheritance = std_inheritance;
+ memcpy (&cm[1], service_name, slen);
+ h->service_test_is_active = GNUNET_YES;
+ GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report,
+ cm);
}
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
- h->client = client;
+ else
+ {
+ /* Service test is already running - tell user to chill out and try
+ * again later.
+ */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service test is already in progress, we're busy\n");
+ if (NULL != cont)
+ cont (cont_cls, h, GNUNET_ARM_REQUEST_BUSY, NULL, 0);
+ }
+ return;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n");
- change_service (h, service_name, timeout, cb, cb_cls,
+ change_service (h, service_name, timeout, cont, cont_cls,
GNUNET_MESSAGE_TYPE_ARM_START);
}
/**
- * Callback from the arm stop service call, indicates that the arm service
- * is well and truly dead, won't die, or an error occurred.
- *
- * @param cls closure for the callback
- * @param reason reason for callback
- */
-static void
-arm_shutdown_callback (void *cls, enum GNUNET_ARM_ProcessStatus reason)
-{
- struct ARM_ShutdownContext *arm_shutdown_ctx = cls;
-
- if (arm_shutdown_ctx->cb != NULL)
- arm_shutdown_ctx->cb (arm_shutdown_ctx->cb_cls, reason);
- GNUNET_free (arm_shutdown_ctx);
-}
-
-
-/**
- * Stop a service.
+ * Request a service to be stopped.
+ * Stopping arm itself will not invalidate its handle, and
+ * ARM API will try to restore connection to the ARM service,
+ * even if ARM connection was lost because you asked for ARM to be stopped.
+ * Call GNUNET_ARM_disconnect () to free the handle and prevent
+ * further connection attempts.
*
* @param h handle to ARM
* @param service_name name of the service
* @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
+ * @param cont callback to invoke after request is sent or is not sent
+ * @param cont_cls closure for callback
*/
void
-GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
- const char *service_name,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_Callback cb, void *cb_cls)
+GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h,
+ const char *service_name, struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_ResultCallback cont, void *cont_cls)
{
- struct ARM_ShutdownContext *arm_shutdown_ctx;
- struct GNUNET_CLIENT_Connection *client;
-
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Stopping service `%s' within %s\n",
service_name,
GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO));
- if (h->client == NULL)
- {
- client = GNUNET_CLIENT_connect ("arm", h->cfg);
- if (client == NULL)
- {
- cb (cb_cls, GNUNET_SYSERR);
- return;
- }
- h->client = client;
- }
- if (0 == strcasecmp ("arm", service_name))
- {
- arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext));
- arm_shutdown_ctx->cb = cb;
- arm_shutdown_ctx->cb_cls = cb_cls;
- arm_service_shutdown (h->client, timeout, &arm_shutdown_callback,
- arm_shutdown_ctx);
- h->client = NULL;
- return;
- }
- change_service (h, service_name, timeout, cb, cb_cls,
+ change_service (h, service_name, timeout, cont, cont_cls,
GNUNET_MESSAGE_TYPE_ARM_STOP);
}
/**
- * Internal state for a list request with ARM.
+ * Request a list of running services.
+ *
+ * @param h handle to ARM
+ * @param timeout how long to wait before failing for good
+ * @param cont callback to invoke after request is sent or is not sent
+ * @param cont_cls closure for callback
*/
-struct ListRequestContext
+void
+GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_ServiceListCallback cont, void *cont_cls)
{
+ struct ARMControlMessage *cm;
+ struct GNUNET_ARM_Message *msg;
- /**
- * Pointer to our handle with ARM.
- */
- struct GNUNET_ARM_Handle *h;
-
- /**
- * Function to call with a status code for the requested operation.
- */
- GNUNET_ARM_List_Callback callback;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting LIST from ARM service with timeout: %s\n",
+ GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES));
- /**
- * Closure for "callback".
- */
- void *cls;
+ cm = GNUNET_malloc (sizeof (struct ARMControlMessage));
+ cm->h = h;
+ cm->list_cont = cont;
+ cm->cont_cls = cont_cls;
+ cm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message));
+ msg->header.size = htons (sizeof (struct GNUNET_ARM_Message));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST);
+ cm->msg = msg;
+ GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head,
+ h->control_pending_tail, cm);
+ cm->timeout_task_id =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (cm->timeout), &control_message_timeout, cm);
+ trigger_next_request (h, GNUNET_NO);
+}
- /**
- * Timeout for the operation.
- */
- struct GNUNET_TIME_Absolute timeout;
-};
+static struct ARMControlMessage *
+find_cm_by_id (struct GNUNET_ARM_Handle *h, uint64_t id)
+{
+ struct ARMControlMessage *result;
+ for (result = h->control_sent_head; result; result = result->next)
+ if (id == result->msg->request_id)
+ return result;
+ return NULL;
+}
/**
- * Process a response from ARM for the list request.
+ * Handler for ARM replies.
*
- * @param cls the list request context
- * @param msg the response
+ * @param cls our "struct GNUNET_ARM_Handle"
+ * @param msg the message received from the arm service
*/
static void
-handle_list_response (void *cls, const struct GNUNET_MessageHeader *msg)
+client_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
{
- struct ListRequestContext *sc = cls;
- const struct GNUNET_ARM_ListResultMessage *res;
+ struct GNUNET_ARM_Handle *h = cls;
+
+ uint16_t msize;
+ uint64_t id;
+ unsigned char fail;
+
+ const struct GNUNET_ARM_Message *arm_msg;
+ const struct GNUNET_ARM_ResultMessage *res;
+ const struct GNUNET_ARM_ListResultMessage *lres;
+ enum GNUNET_ARM_Result result;
+ struct ARMControlMessage *cm;
+
const char *pos;
uint16_t size_check;
uint16_t rcount;
- uint16_t msize;
-
+
if (NULL == msg)
{
- GNUNET_break (0);
- GNUNET_CLIENT_disconnect (sc->h->client);
- sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg);
- GNUNET_assert (NULL != sc->h->client);
- if (sc->callback != NULL)
- sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL);
- GNUNET_free (sc);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Client was disconnected from arm service, trying to reconnect.\n"));
+ reconnect_arm_later (h);
return;
}
-
- if (NULL == sc->callback)
- {
- GNUNET_break (0);
- GNUNET_free (sc);
- return;
- }
msize = ntohs (msg->size);
- if ( (msize < sizeof ( struct GNUNET_ARM_ListResultMessage)) ||
- (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT) )
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Processing message of type %u and size %u from arm service\n",
+ ntohs (msg->type), msize);
+ if (msize < sizeof (struct GNUNET_ARM_Message))
{
GNUNET_break (0);
- sc->callback (sc->cls, GNUNET_NO, 0, NULL);
- GNUNET_free (sc);
+ reconnect_arm_later (h);
return;
}
- size_check = 0;
- res = (const struct GNUNET_ARM_ListResultMessage *) msg;
- rcount = ntohs (res->count);
+ arm_msg = (const struct GNUNET_ARM_Message *) msg;
+ id = GNUNET_ntohll (arm_msg->request_id);
+ cm = find_cm_by_id (h, id);
+ if (NULL == cm)
{
- const char *list[rcount];
- unsigned int i;
-
- pos = (const char *)&res[1];
- for (i=0; i<rcount; i++)
- {
- const char *end = memchr (pos, 0, msize - size_check);
- if (NULL == end)
- {
- GNUNET_break (0);
- sc->callback (sc->cls, GNUNET_NO, 0, NULL);
- GNUNET_free (sc);
- return;
- }
- list[i] = pos;
- size_check += (end - pos) + 1;
- pos = end + 1;
- }
- sc->callback (sc->cls, GNUNET_YES, rcount, list);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message with unknown id %llu\n", id);
+ return;
}
- GNUNET_free (sc);
-}
-
-
-/**
- * List all running services.
- *
- * @param h handle to ARM
- * @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
- */
-void
-GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_List_Callback cb, void *cb_cls)
-{
- struct ListRequestContext *sctx;
- struct GNUNET_MessageHeader msg;
- struct GNUNET_CLIENT_Connection *client;
- if (h->client == NULL)
+ fail = GNUNET_NO;
+ switch (ntohs (msg->type))
{
- client = GNUNET_CLIENT_connect ("arm", h->cfg);
- if (client == NULL)
+ case GNUNET_MESSAGE_TYPE_ARM_RESULT:
+ if (msize < sizeof (struct GNUNET_ARM_ResultMessage))
+ {
+ GNUNET_assert (0);
+ fail = GNUNET_YES;
+ break;
+ }
+ res = (const struct GNUNET_ARM_ResultMessage *) msg;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received response from ARM for service `%s': %u\n",
+ (const char *) &cm->msg[1], ntohs (msg->type));
+ result = (enum GNUNET_ARM_Result) ntohl (res->result);
+ if (NULL != cm->result_cont)
+ cm->result_cont (cm->cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, (const char *) &cm->msg[1], result);
+ break;
+ case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT:
+ if (msize < sizeof (struct GNUNET_ARM_ListResultMessage))
{
GNUNET_break (0);
- cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL);
+ fail = GNUNET_YES;
return;
}
- h->client = client;
- }
-
- sctx = GNUNET_malloc (sizeof (struct RequestContext));
- sctx->h = h;
- sctx->callback = cb;
- sctx->cls = cb_cls;
- sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- msg.size = htons (sizeof (struct GNUNET_MessageHeader));
- msg.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST);
-
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting LIST from ARM service with timeout: %s\n",
- GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES));
-
- if (GNUNET_OK !=
- GNUNET_CLIENT_transmit_and_get_response (sctx->h->client,
- &msg,
- GNUNET_TIME_absolute_get_remaining
- (sctx->timeout),
- GNUNET_YES,
- &handle_list_response,
- sctx))
- {
- GNUNET_break (0);
- if (cb != NULL)
- cb (cb_cls, GNUNET_SYSERR, 0, NULL);
- GNUNET_free (sctx);
+ else
+ {
+ size_check = 0;
+ lres = (const struct GNUNET_ARM_ListResultMessage *) msg;
+ rcount = ntohs (lres->count);
+ {
+ const char *list[rcount];
+ unsigned int i;
+
+ pos = (const char *)&lres[1];
+ for (i = 0; i < rcount; i++)
+ {
+ const char *end = memchr (pos, 0, msize - size_check);
+ if (NULL == end)
+ {
+ GNUNET_break (0);
+ fail = GNUNET_YES;
+ break;
+ }
+ list[i] = pos;
+ size_check += (end - pos) + 1;
+ pos = end + 1;
+ }
+ if (GNUNET_YES == fail)
+ break;
+ if (NULL != cm->list_cont)
+ cm->list_cont (cm->cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, rcount, list);
+ }
+ }
+ break;
+ default:
+ fail = GNUNET_YES;
return;
}
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cm->timeout_task_id);
+ GNUNET_SCHEDULER_cancel (cm->timeout_task_id);
+ GNUNET_CONTAINER_DLL_remove (h->control_sent_head,
+ h->control_sent_tail, cm);
+ GNUNET_free (cm->msg);
+ GNUNET_free (cm);
+
+ if (GNUNET_YES == fail)
+ reconnect_arm_later (h);
+ else
+ GNUNET_CLIENT_receive (h->client, &client_notify_handler, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
}
/* end of arm_api.c */
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c
index 8a98ba06b3..9eb64e316d 100644
--- a/src/arm/gnunet-arm.c
+++ b/src/arm/gnunet-arm.c
@@ -111,6 +111,11 @@ static int ret;
static struct GNUNET_ARM_Handle *h;
/**
+ * Monitor connection with ARM.
+ */
+static struct GNUNET_ARM_MonitorHandle *m;
+
+/**
* Our configuration.
*/
static struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -137,105 +142,6 @@ static unsigned int no_stderr;
/**
- * Main continuation-passing-style loop. Runs the various
- * jobs that we've been asked to do in order.
- *
- * @param cls closure, unused
- * @param tc context, unused
- */
-static void
-cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Callback invoked with the status of the last operation. Reports to the
- * user and then runs the next phase in the FSM.
- *
- * @param cls pointer to "const char*" identifying service that was manipulated
- * @param result result of the operation
- */
-static void
-confirm_cb (void *cls,
- enum GNUNET_ARM_ProcessStatus result)
-{
- const char *service = cls;
-
- switch (result)
- {
- case GNUNET_ARM_PROCESS_UNKNOWN:
- FPRINTF (stderr, _("Service `%s' is unknown to ARM.\n"), service);
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_DOWN:
- if (quiet != GNUNET_YES)
- FPRINTF (stdout, _("Service `%s' has been stopped.\n"), service);
- break;
- case GNUNET_ARM_PROCESS_ALREADY_RUNNING:
- FPRINTF (stderr, _("Service `%s' was already running.\n"), service);
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_STARTING:
- if (quiet != GNUNET_YES)
- FPRINTF (stdout, _("Service `%s' has been started.\n"), service);
- break;
- case GNUNET_ARM_PROCESS_ALREADY_STOPPING:
- FPRINTF (stderr, _("Service `%s' was already being stopped.\n"), service);
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_ALREADY_DOWN:
- FPRINTF (stderr, _("Service `%s' was already not running.\n"), service);
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_SHUTDOWN:
- FPRINTF (stderr, "%s", _("Request ignored as ARM is shutting down.\n"));
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR:
- FPRINTF (stderr, "%s", _("Error communicating with ARM service.\n"));
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT:
- FPRINTF (stderr, "%s", _("Timeout communicating with ARM service.\n"));
- ret = 1;
- break;
- case GNUNET_ARM_PROCESS_FAILURE:
- FPRINTF (stderr, "%s", _("Operation failed.\n"));
- ret = 1;
- break;
- default:
- FPRINTF (stderr, "%s", _("Unknown response code from ARM.\n"));
- break;
- }
- GNUNET_SCHEDULER_add_now (&cps_loop, NULL);
-}
-
-
-/**
- * Callback invoked with the list of running services.
- * Reports to the user and then runs the next phase in the FSM.
- *
- * @param cls currently not used
- * @param result result of the operation
- * @param count number of running services
- * @param list copy of the list of running services
- */
-static void
-list_cb (void *cls, int result, unsigned int count, const char *const*list)
-{
- unsigned int i;
-
- if ( (result != GNUNET_YES) || (NULL == list) )
- {
- FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n"));
- return;
- }
- FPRINTF (stdout, "%s", _("Running services:\n"));
- for (i=0; i<count; i++)
- FPRINTF (stdout, "%s\n", list[i]);
-}
-
-
-/**
* Attempts to delete configuration file and SERVICEHOME
* on arm shutdown provided the end and delete options
* were specified when gnunet-arm was run.
@@ -273,7 +179,9 @@ static void
shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
GNUNET_ARM_disconnect (h);
+ GNUNET_ARM_monitor_disconnect (m);
h = NULL;
+ m = NULL;
if ((end == GNUNET_YES) && (delete == GNUNET_YES))
delete_files ();
GNUNET_CONFIGURATION_destroy (cfg);
@@ -281,68 +189,248 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
}
+static const char *
+req_string (enum GNUNET_ARM_RequestStatus rs)
+{
+ switch (rs)
+ {
+ case GNUNET_ARM_REQUEST_SENT_OK:
+ return _("Message was sent successfully");
+ case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
+ return _("Misconfiguration (can't connect to the ARM service)");
+ case GNUNET_ARM_REQUEST_DISCONNECTED:
+ return _("We disconnected from ARM before we could send a request");
+ case GNUNET_ARM_REQUEST_BUSY:
+ return _("ARM API is busy");
+ case GNUNET_ARM_REQUEST_TOO_LONG:
+ return _("Request doesn't fit into a message");
+ case GNUNET_ARM_REQUEST_TIMEOUT:
+ return _("Request timed out");
+ default:
+ return _("Unknown request status");
+ }
+}
+
+static const char *
+ret_string (enum GNUNET_ARM_Result result)
+{
+ switch (result)
+ {
+ case GNUNET_ARM_RESULT_STOPPED:
+ return _("%s is stopped");
+ case GNUNET_ARM_RESULT_STARTING:
+ return _("%s is starting");
+ case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
+ return _("%s is starting already");
+ case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
+ return _("%s is stopping already");
+ case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
+ return _("%s is started already");
+ case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
+ return _("%s is stopped already");
+ case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
+ return _("%s service is not known to ARM");
+ case GNUNET_ARM_RESULT_START_FAILED:
+ return _("%s service failed to start");
+ case GNUNET_ARM_RESULT_IN_SHUTDOWN:
+ return _("%s service can't be started because ARM is shutting down");
+ default:
+ return _("Unknown result code.");
+ }
+}
+
+static void action_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
/**
- * Main function that will be run by the scheduler.
+ * Function called whenever we connect to or disconnect from ARM.
*
* @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
+ * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected
+ * @param error GNUNET_YES if we encountered a permanent error, and there
+ * will be no re-connection.
*/
+void
+conn_status (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error)
+{
+ if (GNUNET_YES == error)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Fatal error initializing ARM API.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+/*
+ if (connected)
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
+*/
+}
+
+
static void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
+term_callback (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, const char *service,
+ enum GNUNET_ARM_Result result)
{
- char *armconfig;
+ if (GNUNET_ARM_REQUEST_SENT_OK != rs)
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, _("Failed to send a request to kill the `%s' service: %%s\n"), term);
+ FPRINTF (stdout, msg, req_string (rs));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ if ((GNUNET_ARM_RESULT_STOPPED == result) ||
+ (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service %s shutdown successful\n", term);
+ term = NULL;
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
+ }
+ else
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, _("Failed to kill the `%s' service: %%s\n"), term);
+ FPRINTF (stdout, msg, ret_string (result));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+}
- cfg = GNUNET_CONFIGURATION_dup (c);
- config_file = cfgfile;
- if (GNUNET_CONFIGURATION_get_value_string
- (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK)
+static void
+end_callback (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, const char *service,
+ enum GNUNET_ARM_Result result)
+{
+ if (GNUNET_ARM_REQUEST_SENT_OK != rs)
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "PATHS", "SERVICEHOME");
- return;
- }
- if (NULL != cfgfile)
+ char *msg;
+ GNUNET_asprintf (&msg, "%s", _("Failed to send a stop request to the ARM service: %%s\n"));
+ FPRINTF (stdout, msg, req_string (rs));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ if ((GNUNET_ARM_RESULT_STOPPING == result) ||
+ (GNUNET_ARM_RESULT_STOPPED == result) ||
+ (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result))
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG",
- &armconfig))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service shutdown successful\n");
+ end = 0;
+ if (restart)
{
- GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
- cfgfile);
+ restart = 0;
+ start = 1;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initiating an ARM restart\n");
}
- else
- GNUNET_free (armconfig);
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
}
- if (NULL == (h = GNUNET_ARM_connect (cfg, NULL)))
+ else
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Fatal error initializing ARM API.\n"));
- ret = 1;
- GNUNET_CONFIGURATION_destroy (cfg);
- cfg = NULL;
+ char *msg;
+ GNUNET_asprintf (&msg, "%s", _("Failed to stop the ARM service: %%s\n"));
+ FPRINTF (stdout, msg, ret_string (result));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+}
+
+static void
+start_callback (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, const char *service,
+ enum GNUNET_ARM_Result result)
+{
+ if (GNUNET_ARM_REQUEST_SENT_OK != rs)
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %%s\n"));
+ FPRINTF (stdout, msg, req_string (rs));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ if ((GNUNET_ARM_RESULT_STARTING == result) ||
+ (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service [re]start successful\n");
+ start = 0;
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
+ }
+ else
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %%s\n"));
+ FPRINTF (stdout, msg, ret_string (result));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+}
+
+
+static void
+init_callback (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, const char *service,
+ enum GNUNET_ARM_Result result)
+{
+ if (GNUNET_ARM_REQUEST_SENT_OK != rs)
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, _("Failed to send a request to start the `%s' service: %%s\n"), init);
+ FPRINTF (stdout, msg, req_string (rs));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ if ((GNUNET_ARM_RESULT_STARTING == result) ||
+ (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service %s [re]start successful\n", init);
+ init = NULL;
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
+ }
+ else
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, _("Failed to start the `%s' service: %%s\n"), init);
+ FPRINTF (stdout, msg, ret_string (result));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+}
+
+
+static void
+list_callback (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, unsigned int count,
+ const char *const*list)
+{
+ unsigned int i;
+ if (GNUNET_ARM_REQUEST_SENT_OK != rs)
+ {
+ char *msg;
+ GNUNET_asprintf (&msg, "%s", _("Failed to request a list of services: %%s\n"));
+ FPRINTF (stdout, msg, req_string (rs));
+ GNUNET_free (msg);
+ GNUNET_SCHEDULER_shutdown ();
+ }
+ if (NULL == list)
+ {
+ FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n"));
return;
}
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &shutdown_task, NULL);
- GNUNET_SCHEDULER_add_now (&cps_loop, NULL);
+ FPRINTF (stdout, "%s", _("Running services:\n"));
+ for (i = 0; i < count; i++)
+ FPRINTF (stdout, "%s\n", list[i]);
}
/**
- * Main continuation-passing-style loop. Runs the various
+ * Main action loop. Runs the various
* jobs that we've been asked to do in order.
*
* @param cls closure, unused
* @param tc context, unused
*/
static void
-cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+action_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- if (NULL == h)
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running requested actions\n");
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
while (1)
@@ -352,82 +440,54 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
case 0:
if (NULL != term)
{
- GNUNET_ARM_stop_service (h, term,
- (0 ==
- timeout.rel_value) ? STOP_TIMEOUT :
- timeout, &confirm_cb, term);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Termination action\n");
+ GNUNET_ARM_request_service_stop (h, term, (0 ==
+ timeout.rel_value) ? STOP_TIMEOUT : timeout,
+ term_callback, NULL);
return;
}
break;
case 1:
- if ((end) || (restart))
+ if (end || restart)
{
- GNUNET_ARM_stop_service (h, "arm",
- (0 ==
- timeout.rel_value) ? STOP_TIMEOUT_ARM
- : timeout, &confirm_cb, "arm");
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "End action\n");
+ GNUNET_ARM_request_service_stop (h, "arm", (0 ==
+ timeout.rel_value) ? STOP_TIMEOUT_ARM : timeout,
+ end_callback, NULL);
+ return;
}
break;
case 2:
if (start)
{
- GNUNET_ARM_start_service (h, "arm",
- (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
- (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
- (0 ==
- timeout.rel_value) ? START_TIMEOUT :
- timeout, &confirm_cb, "arm");
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start action\n");
+ GNUNET_ARM_request_service_start (h, "arm",
+ (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
+ (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
+ (0 == timeout.rel_value) ? START_TIMEOUT: timeout,
+ start_callback, NULL);
+ return;
}
break;
case 3:
if (NULL != init)
- {
- GNUNET_ARM_start_service (h, init,
- (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) |
- (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR),
- (0 ==
- timeout.rel_value) ? START_TIMEOUT :
- timeout, &confirm_cb, init);
- return;
- }
- break;
- case 4:
- if (restart)
{
- GNUNET_ARM_disconnect (h);
- phase = 0;
- end = 0;
- start = 1;
- restart = 0;
- if (NULL == (h = GNUNET_ARM_connect (cfg, NULL)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Fatal error initializing ARM API.\n"));
- ret = 1;
- return;
- }
- GNUNET_SCHEDULER_add_now (&cps_loop, NULL);
- return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initialization action\n");
+ GNUNET_ARM_request_service_start (h, init, GNUNET_OS_INHERIT_STD_NONE,
+ (0 == timeout.rel_value) ? STOP_TIMEOUT : timeout,
+ init_callback, NULL);
+ return;
}
break;
- case 5:
+ case 4:
if (list)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Going to list all running services controlled by ARM.\n");
- if (NULL == h)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Fatal error initializing ARM API.\n"));
- return;
- }
- GNUNET_ARM_list_running_services (h,
- (0 ==
- timeout.rel_value) ? LIST_TIMEOUT :
- timeout, &list_cb, NULL);
+ GNUNET_ARM_request_service_list (h,
+ (0 == timeout.rel_value) ? LIST_TIMEOUT : timeout,
+ list_callback, &list);
return;
}
/* Fall through */
@@ -440,6 +500,89 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
/**
+ * Function called when a service starts or stops.
+ *
+ * @param cls closure
+ * @param service service name
+ * @param status status of the service
+ */
+static void
+srv_status (void *cls, struct GNUNET_ARM_MonitorHandle *arm,
+ const char *service, enum GNUNET_ARM_ServiceStatus status)
+{
+ const char *msg;
+ switch (status)
+ {
+ case GNUNET_ARM_SERVICE_MONITORING_STARTED:
+ msg = _("Began monitoring ARM for service status changes\n");
+ break;
+ case GNUNET_ARM_SERVICE_STOPPED:
+ msg = _("Stopped %s.\n");
+ break;
+ case GNUNET_ARM_SERVICE_STARTING:
+ msg = _("Starting %s...\n");
+ break;
+ case GNUNET_ARM_SERVICE_STOPPING:
+ msg = _("Stopping %s...\n");
+ break;
+ default:
+ msg = NULL;
+ break;
+ }
+ if (NULL != msg)
+ FPRINTF (stderr, msg, service);
+ else
+ FPRINTF (stderr, _("Unknown status %u for service %s.\n"), status, service);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got service %s status %u\n", service, status);
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ char *armconfig;
+
+ cfg = GNUNET_CONFIGURATION_dup (c);
+ config_file = cfgfile;
+ if (GNUNET_CONFIGURATION_get_value_string
+ (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK)
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "PATHS", "SERVICEHOME");
+ return;
+ }
+ if (NULL != cfgfile)
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG",
+ &armconfig))
+ {
+ GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG",
+ cfgfile);
+ }
+ else
+ GNUNET_free (armconfig);
+ }
+ h = GNUNET_ARM_alloc (cfg);
+ m = GNUNET_ARM_monitor_alloc (cfg);
+ GNUNET_ARM_connect (h, conn_status, NULL);
+ GNUNET_ARM_monitor (m, srv_status, NULL);
+ GNUNET_SCHEDULER_add_now (action_loop, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ shutdown_task, NULL);
+}
+
+
+/**
* The main function to obtain arm from gnunetd.
*
* @param argc number of arguments from the command line
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 7a99b5079f..b1ba5af1bc 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -30,6 +30,13 @@
#include "arm.h"
/**
+ * How many messages do we queue up at most for optional
+ * notifications to a client? (this can cause notifications
+ * about outgoing messages to be dropped).
+ */
+#define MAX_NOTIFY_QUEUE 1024
+
+/**
* List of our services.
*/
struct ServiceList;
@@ -125,6 +132,11 @@ struct ServiceList
struct GNUNET_SERVER_Client *killing_client;
/**
+ * ID of the request that killed the service (for reporting back).
+ */
+ uint64_t killing_client_request_id;
+
+ /**
* Process structure pointer of the child.
*/
struct GNUNET_OS_Process *proc;
@@ -217,17 +229,154 @@ static int in_shutdown;
*/
static struct GNUNET_SERVER_Handle *server;
+/**
+ * Context for notifications we need to send to our clients.
+ */
+static struct GNUNET_SERVER_NotificationContext *notifier;
+
#include "do_start_process.c"
+/**
+ * Transmit a status result message.
+ *
+ * @param cls pointer to "unit16_t*" with message type
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message, NULL on error
+ * @return number of bytes copied to buf
+ */
+static size_t
+write_result (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_ARM_ResultMessage *msg = cls;
+ size_t msize;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not send status result to client\n"));
+ GNUNET_free (msg);
+ return 0; /* error, not much we can do */
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending status response %u to client\n", (unsigned int) msg->result);
+ msize = msg->arm_msg.header.size;
+ GNUNET_assert (size >= msize);
+ msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
+ msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
+ msg->result = htonl (msg->result);
+ msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
+ memcpy (buf, msg, msize);
+ GNUNET_free (msg);
+ return msize;
+}
+
+/**
+ * Transmit the list of running services.
+ *
+ * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message, NULL on error
+ * @return number of bytes copied to buf
+ */
+static size_t
+write_list_result (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_ARM_ListResultMessage *msg = cls;
+ size_t rslt_size;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not send list result to client\n"));
+ GNUNET_free (msg);
+ return 0; /* error, not much we can do */
+ }
+
+ rslt_size = msg->arm_msg.header.size;
+ GNUNET_assert (size >= rslt_size);
+ msg->arm_msg.header.size = htons (msg->arm_msg.header.size);
+ msg->arm_msg.header.type = htons (msg->arm_msg.header.type);
+ msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id);
+ msg->count = htons (msg->count);
+
+ memcpy (buf, msg, rslt_size);
+ GNUNET_free (msg);
+ return rslt_size;
+}
+
+
+/**
+ * Signal our client that we will start or stop the
+ * service.
+ *
+ * @param client who is being signalled
+ * @param name name of the service
+ * @param result message type to send
+ * @return NULL if it was not found
+ */
+static void
+signal_result (struct GNUNET_SERVER_Client *client, const char *name,
+ uint64_t request_id, enum GNUNET_ARM_Result result)
+{
+ struct GNUNET_ARM_ResultMessage *msg;
+ size_t msize;
+
+ msize = sizeof (struct GNUNET_ARM_ResultMessage);
+ msg = GNUNET_malloc (msize);
+ msg->arm_msg.header.size = msize;
+ msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_RESULT;
+ msg->result = result;
+ msg->arm_msg.request_id = request_id;
+
+ GNUNET_SERVER_notify_transmit_ready (client, msize,
+ GNUNET_TIME_UNIT_FOREVER_REL, write_result, msg);
+}
+
+
+/**
+ * Tell all clients about status change of a service.
+ *
+ * @param name name of the service
+ * @param status message type to send
+ */
+static void
+broadcast_status (const char *name, enum GNUNET_ARM_ServiceStatus status,
+ struct GNUNET_SERVER_Client *unicast)
+{
+ struct GNUNET_ARM_StatusMessage *msg;
+ size_t namelen;
+
+ if (NULL == notifier)
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending status %u of service `%s' to client\n",
+ (unsigned int) status, name);
+ namelen = strlen (name);
+ msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
+ msg->header.size = htons (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_STATUS);
+ msg->status = htonl ((uint32_t) (status));
+ memcpy ((char *) &msg[1], name, namelen + 1);
+
+ if (NULL == unicast)
+ GNUNET_SERVER_notification_context_broadcast (notifier,
+ (struct GNUNET_MessageHeader *) msg, GNUNET_YES);
+ else
+ GNUNET_SERVER_notification_context_unicast (notifier, unicast,
+ (const struct GNUNET_MessageHeader *) msg, GNUNET_NO);
+ GNUNET_free (msg);
+}
+
/**
* Actually start the process for the given service.
*
* @param sl identifies service to start
+ * @param client that asked to start the service (may be NULL)
*/
static void
-start_process (struct ServiceList *sl)
+start_process (struct ServiceList *sl, struct GNUNET_SERVER_Client *client, uint64_t request_id)
{
char *loprefix;
char *options;
@@ -342,11 +491,20 @@ start_process (struct ServiceList *sl)
}
GNUNET_free (binary);
if (sl->proc == NULL)
+ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"),
sl->name);
+ if (client)
+ signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_START_FAILED);
+ }
else
+ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"),
sl->name);
+ broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL);
+ if (client)
+ signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING);
+ }
/* clean up */
GNUNET_free (loprefix);
GNUNET_free (options);
@@ -355,104 +513,6 @@ start_process (struct ServiceList *sl)
/**
- * Transmit a status result message.
- *
- * @param cls pointer to "unit16_t*" with message type
- * @param size number of bytes available in buf
- * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to buf
- */
-static size_t
-write_result (void *cls, size_t size, void *buf)
-{
- enum GNUNET_ARM_ProcessStatus *res = cls;
- struct GNUNET_ARM_ResultMessage *msg;
-
- if (buf == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Could not send status result to client\n"));
- return 0; /* error, not much we can do */
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending status response %u to client\n", (unsigned int) *res);
- GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage));
- msg = buf;
- msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage));
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT);
- msg->status = htonl ((uint32_t) (*res));
- GNUNET_free (res);
- return sizeof (struct GNUNET_ARM_ResultMessage);
-}
-
-/**
- * Transmit the list of running services.
- *
- * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message
- * @param size number of bytes available in buf
- * @param buf where to copy the message, NULL on error
- * @return number of bytes copied to buf
- */
-static size_t
-write_list_result (void *cls, size_t size, void *buf)
-{
- struct GNUNET_ARM_ListResultMessage *msg = cls;
- struct GNUNET_ARM_ListResultMessage *rslt;
- size_t rslt_size;
-
- if (buf == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Could not send list result to client\n"));
- return 0; /* error, not much we can do */
- }
-
- GNUNET_assert (size >= msg->header.size);
- rslt = buf;
- rslt->header.size = htons (msg->header.size);
- rslt->header.type = htons (msg->header.type);
- rslt->count = htons (msg->count);
-
- size_t list_size = msg->header.size
- - sizeof (struct GNUNET_ARM_ListResultMessage);
- memcpy (&rslt[1], &msg[1], list_size);
-
- rslt_size = msg->header.size;
- GNUNET_free (msg);
- return rslt_size;
-}
-
-
-/**
- * Signal our client that we will start or stop the
- * service.
- *
- * @param client who is being signalled
- * @param name name of the service
- * @param result message type to send
- * @return NULL if it was not found
- */
-static void
-signal_result (struct GNUNET_SERVER_Client *client, const char *name,
- enum GNUNET_ARM_ProcessStatus result)
-{
- enum GNUNET_ARM_ProcessStatus *res;
-
- if (NULL == client)
- return;
- /* FIXME: this is not super-clean yet... */
- res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus));
- *res = result;
- GNUNET_SERVER_notify_transmit_ready (client,
- sizeof (struct
- GNUNET_ARM_ResultMessage),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &write_result, res);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
* Find the process with the given service
* name in the given list and return it.
*
@@ -492,7 +552,7 @@ accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
GNUNET_assert (GNUNET_NO == in_shutdown);
if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
return;
- start_process (sl);
+ start_process (sl, NULL, 0);
}
@@ -619,10 +679,14 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
const char *servicename;
struct ServiceList *sl;
uint16_t size;
-
- size = ntohs (message->size);
- size -= sizeof (struct GNUNET_MessageHeader);
- servicename = (const char *) &message[1];
+ uint64_t request_id;
+ struct GNUNET_ARM_Message *amsg;
+
+ amsg = (struct GNUNET_ARM_Message *) message;
+ request_id = GNUNET_ntohll (amsg->request_id);
+ size = ntohs (amsg->header.size);
+ size -= sizeof (struct GNUNET_ARM_Message);
+ servicename = (const char *) &amsg[1];
if ((size == 0) || (servicename[size - 1] != '\0'))
{
GNUNET_break (0);
@@ -631,23 +695,40 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client,
}
if (GNUNET_YES == in_shutdown)
{
- signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
sl = find_service (servicename);
if (NULL == sl)
{
- signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
sl->is_default = GNUNET_YES;
if (sl->proc != NULL)
{
- signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_STARTED_ALREADY);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
- start_process (sl);
- signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING);
+ start_process (sl, client, request_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Start a shutdown sequence.
+ *
+ * @param cls closure (refers to service)
+ * @param tc task context
+ */
+static void
+trigger_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n");
+ GNUNET_SCHEDULER_shutdown ();
}
@@ -667,10 +748,14 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
struct ServiceList *sl;
const char *servicename;
uint16_t size;
-
- size = ntohs (message->size);
- size -= sizeof (struct GNUNET_MessageHeader);
- servicename = (const char *) &message[1];
+ uint64_t request_id;
+ struct GNUNET_ARM_Message *amsg;
+
+ amsg = (struct GNUNET_ARM_Message *) message;
+ request_id = GNUNET_ntohll (amsg->request_id);
+ size = ntohs (amsg->header.size);
+ size -= sizeof (struct GNUNET_ARM_Message);
+ servicename = (const char *) &amsg[1];
if ((size == 0) || (servicename[size - 1] != '\0'))
{
GNUNET_break (0);
@@ -679,40 +764,58 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Preparing to stop `%s'\n"), servicename);
+ if (0 == strcasecmp (servicename, "arm"))
+ {
+ broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING);
+ GNUNET_SERVER_client_persist_ (client);
+ GNUNET_SCHEDULER_add_now (trigger_shutdown, NULL);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
sl = find_service (servicename);
if (sl == NULL)
{
- signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
sl->is_default = GNUNET_NO;
if (GNUNET_YES == in_shutdown)
{
/* shutdown in progress */
- signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN);
+ signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
if (sl->killing_client != NULL)
{
/* killing already in progress */
- signal_result (client, servicename,
- GNUNET_ARM_PROCESS_ALREADY_STOPPING);
+ signal_result (client, servicename, request_id,
+ GNUNET_ARM_RESULT_IS_STOPPING_ALREADY);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
if (sl->proc == NULL)
{
/* process is down */
- signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN);
+ signal_result (client, servicename, request_id,
+ GNUNET_ARM_RESULT_IS_STOPPED_ALREADY);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending kill signal to service `%s', waiting for process to die.\n",
servicename);
+ broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL);
+ /* no signal_start - only when it's STOPPED */
sl->killed_at = GNUNET_TIME_absolute_get ();
if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
sl->killing_client = client;
+ sl->killing_client_request_id = request_id;
GNUNET_SERVER_client_keep (client);
+ GNUNET_SERVER_receive_done (client, GNUNET_YES);
}
/**
@@ -727,6 +830,7 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
struct GNUNET_ARM_ListResultMessage *msg;
+ struct GNUNET_ARM_Message *request;
size_t string_list_size;
size_t total_size;
struct ServiceList *sl;
@@ -735,6 +839,7 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
if (NULL == client)
return;
+ request = (struct GNUNET_ARM_Message *) message;
count = 0;
string_list_size = 0;
/* first count the running processes get their name's size */
@@ -748,11 +853,13 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
count++;
}
}
+
total_size = sizeof (struct GNUNET_ARM_ListResultMessage)
+ string_list_size;
msg = GNUNET_malloc (total_size);
- msg->header.size = total_size;
- msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
+ msg->arm_msg.header.size = total_size;
+ msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT;
+ msg->arm_msg.request_id = GNUNET_ntohll (request->request_id);
msg->count = count;
char *pos = (char *)&msg[1];
@@ -767,9 +874,9 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
}
GNUNET_SERVER_notify_transmit_ready (client,
- msg->header.size,
+ total_size,
GNUNET_TIME_UNIT_FOREVER_REL,
- &write_list_result, msg);
+ write_list_result, msg);
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
@@ -780,6 +887,12 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client,
static void
do_shutdown ()
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n");
+ if (NULL != notifier)
+ {
+ GNUNET_SERVER_notification_context_destroy (notifier);
+ notifier = NULL;
+ }
if (NULL != server)
{
GNUNET_SERVER_destroy (server);
@@ -792,6 +905,15 @@ do_shutdown ()
}
}
+unsigned int
+list_count (struct ServiceList *running_head)
+{
+ struct ServiceList *i;
+ unsigned int res = 0;
+ for (res = 0, i = running_head; i; i = i->next, res++)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", i->name);
+ return res;
+}
/**
* Task run for shutdown.
@@ -806,6 +928,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
struct ServiceList *nxt;
struct ServiceListeningInfo *sli;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n");
if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
{
GNUNET_SCHEDULER_cancel (child_restart_task);
@@ -851,6 +974,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
/* finally, should all service processes be already gone, terminate for real */
if (running_head == NULL)
do_shutdown ();
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Delaying shutdown, have %u childs still running\n", list_count (running_head));
}
@@ -890,7 +1016,7 @@ delayed_restart_task (void *cls,
/* process should run by default, start immediately */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Restarting service `%s'.\n"), sl->name);
- start_process (sl);
+ start_process (sl, NULL, 0);
}
else
{
@@ -1004,74 +1130,63 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
}
GNUNET_OS_process_destroy (pos->proc);
pos->proc = NULL;
+ broadcast_status (pos->name, GNUNET_ARM_SERVICE_STOPPED, NULL);
if (NULL != pos->killing_client)
- {
- signal_result (pos->killing_client, pos->name,
- GNUNET_ARM_PROCESS_DOWN);
- GNUNET_SERVER_client_drop (pos->killing_client);
- pos->killing_client = NULL;
- /* process can still be re-started on-demand, ensure it is re-started if there is demand */
- for (sli = pos->listen_head; NULL != sli; sli = sli->next)
- {
- GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
- sli->accept_task =
- GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- sli->listen_socket,
- &accept_connection, sli);
- }
- }
+ {
+ signal_result (pos->killing_client, pos->name,
+ pos->killing_client_request_id, GNUNET_ARM_RESULT_STOPPED);
+ GNUNET_SERVER_client_drop (pos->killing_client);
+ pos->killing_client = NULL;
+ pos->killing_client_request_id = 0;
+ /* process can still be re-started on-demand, ensure it is re-started if there is demand */
+ for (sli = pos->listen_head; NULL != sli; sli = sli->next)
+ {
+ GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task);
+ sli->accept_task =
+ GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ sli->listen_socket, &accept_connection, sli);
+ }
+ }
if (GNUNET_YES != in_shutdown)
- {
- if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
- {
- /* process terminated normally, allow restart at any time */
- pos->restart_at.abs_value = 0;
- }
- else
- {
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _
- ("Service `%s' terminated with status %s/%d, will restart in %s\n"),
- pos->name, statstr, statcode,
- GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES));
- /* schedule restart */
- pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
- pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
- }
- if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
- GNUNET_SCHEDULER_cancel (child_restart_task);
- child_restart_task =
- GNUNET_SCHEDULER_add_with_priority
- (GNUNET_SCHEDULER_PRIORITY_IDLE,
- &delayed_restart_task, NULL);
+ {
+ if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
+ {
+ /* process terminated normally, allow restart at any time */
+ pos->restart_at.abs_value = 0;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Service `%s' terminated normally, will restart at any time\n"),
+ pos->name);
}
+ else
+ {
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
+ pos->name, statstr, statcode,
+ GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES));
+ /* schedule restart */
+ pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff);
+ pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != child_restart_task)
+ GNUNET_SCHEDULER_cancel (child_restart_task);
+ child_restart_task = GNUNET_SCHEDULER_add_with_priority (
+ GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL);
+ }
else
- {
- free_service (pos);
- }
+ {
+ free_service (pos);
+ }
}
- child_death_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &maint_child_death, NULL);
+ child_death_task = GNUNET_SCHEDULER_add_read_file (
+ GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL);
if ((NULL == running_head) && (GNUNET_YES == in_shutdown))
do_shutdown ();
-}
-
+ else if (GNUNET_YES == in_shutdown)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Delaying shutdown after child's death, still have %u children\n",
+ list_count (running_head));
-/**
- * Handler for SHUTDOWN message.
- *
- * @param cls closure (refers to service)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_SERVER_client_persist_ (client);
}
@@ -1174,6 +1289,43 @@ setup_service (void *cls, const char *section)
/**
+ * A client connected, add it to the notification context.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+static void
+handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ /* All clients are considered to be of the "monitor" kind
+ * (that is, they don't affect ARM shutdown).
+ */
+ if (NULL != client)
+ GNUNET_SERVER_client_mark_monitor (client);
+}
+
+/**
+ * Handle MONITOR-message.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ * @return GNUNET_OK to keep the connection open,
+ * GNUNET_SYSERR to close it (signal serious error)
+ */
+static void
+handle_monitor (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ /* Removal is handled by the server implementation, internally. */
+ if ((NULL != client) && (NULL != notifier))
+ {
+ GNUNET_SERVER_notification_context_add (notifier, client);
+ broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client);
+ }
+}
+
+/**
* Process arm requests.
*
* @param cls closure
@@ -1187,8 +1339,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
static const struct GNUNET_SERVER_MessageHandler handlers[] = {
{&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0},
{&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0},
- {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
- sizeof (struct GNUNET_MessageHeader)},
+ {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR, 0},
{&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST,
sizeof (struct GNUNET_MessageHeader)},
{NULL, NULL, 0, 0}
@@ -1241,7 +1392,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
continue;
}
sl->is_default = GNUNET_YES;
- start_process (sl);
+ start_process (sl, NULL, 0);
}
}
GNUNET_free (defaultservices);
@@ -1253,6 +1404,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv,
("No default services configured, GNUnet will not really start right now.\n"));
}
+ notifier =
+ GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
+ GNUNET_SERVER_connect_notify (server, handle_client_connecting, NULL);
/* process client requests */
GNUNET_SERVER_add_handlers (server, handlers);
}
diff --git a/src/arm/mockup-service.c b/src/arm/mockup-service.c
index d9896997be..2e021627e4 100644
--- a/src/arm/mockup-service.c
+++ b/src/arm/mockup-service.c
@@ -29,21 +29,27 @@
#include "gnunet_time_lib.h"
+static int special_ret = 0;
+
/**
- * Handler for SHUTDOWN message.
+ * Handler for STOP message.
*
* @param cls closure (refers to service)
* @param client identification of the client
* @param message the actual message
*/
static void
-handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client,
+handle_stop (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Initiating shutdown as requested by client.\n"));
GNUNET_SERVER_client_persist_ (client);
GNUNET_SCHEDULER_shutdown ();
+ /* ARM won't exponentially increase restart delay if we
+ * terminate normally. This changes the return code.
+ */
+ special_ret = 1;
}
@@ -52,7 +58,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN,
+ {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP,
sizeof (struct GNUNET_MessageHeader)},
{NULL, NULL, 0, 0}
};
@@ -70,5 +76,7 @@ main (int argc, char *const *argv)
(GNUNET_OK ==
GNUNET_SERVICE_run (argc, argv, "do-nothing", GNUNET_SERVICE_OPTION_NONE,
&run, NULL)) ? 0 : 1;
+ if (0 != special_ret)
+ return special_ret;
return ret;
}
diff --git a/src/arm/test_arm_api.c b/src/arm/test_arm_api.c
index 366d4e500a..999bd77e69 100644
--- a/src/arm/test_arm_api.c
+++ b/src/arm/test_arm_api.c
@@ -42,77 +42,144 @@ static struct GNUNET_ARM_Handle *arm;
static int ok = 1;
+static int phase = 0;
+
static void
-arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success)
+arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
{
- GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN);
- if (success != GNUNET_ARM_PROCESS_DOWN)
- ok = 3;
- else if (ok == 1)
- ok = 0;
+ /* (6), a stop request should be sent to ARM successfully */
+ /* ARM should report that it is stopping */
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING);
+ GNUNET_break (phase == 6);
+ phase++;
+ FPRINTF (stderr, "Sent 'STOP' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
}
-
static void
-arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus success)
+resolver_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
{
- GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN);
+ /* (5), a stop request should be sent to ARM successfully.
+ * ARM should report that resolver is stopped.
+ */
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED);
+ GNUNET_break (phase == 5);
+ FPRINTF (stderr, "Sent 'STOP' request for resolver to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
+ phase++;
#if START_ARM
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
+ GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL);
+#else
+ arm_stop_cb (NULL, GNUNET_ARM_STATUS_SENT_OK, "arm", GNUNET_ARM_SERVICE_STOPPING);
+ arm_conn (NULL, GNUNET_NO, GNUNET_NO);
#endif
}
-
static void
dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen)
{
if (addr == NULL)
{
+ /* (4), resolver should finish resolving localhost */
+ GNUNET_break (phase == 4);
+ phase++;
+ FPRINTF (stderr, "%s", "Finished resolving localhost\n");
if (ok != 0)
- {
- GNUNET_break (0);
- ok = 2;
- }
- GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop,
- NULL);
+ ok = 2;
+ GNUNET_ARM_request_service_stop (arm, "resolver", TIMEOUT, resolver_stop_cb, NULL);
return;
}
+ /* (3), resolver should resolve localhost */
+ GNUNET_break (phase == 3);
+ FPRINTF (stderr, "%s", "Resolved localhost\n");
+ phase++;
GNUNET_break (addr != NULL);
ok = 0;
}
-
static void
-resolver_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
+resolver_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
{
- if (success != GNUNET_ARM_PROCESS_STARTING)
- {
- GNUNET_break (0);
- ok = 2;
-#if START_ARM
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
-#endif
- return;
- }
+ /* (2), the start request for resolver should be sent successfully
+ * ARM should report that resolver service is starting.
+ */
+ GNUNET_assert (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (phase == 2);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
+ FPRINTF (stderr, "Sent 'START' request for resolver to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
+ phase++;
GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL);
}
-
static void
-arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
+trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- if (success != GNUNET_ARM_PROCESS_STARTING)
- {
- GNUNET_break (0);
- ok = 2;
+ GNUNET_ARM_disconnect ((struct GNUNET_ARM_Handle *) cls);
+}
+
+
+void
+arm_conn (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error)
+{
+ if (GNUNET_YES == error)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Fatal error initializing ARM API.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ GNUNET_assert (0);
+ return;
+ }
+ if (connected)
+ {
+ /* (1), arm connection should be established */
+ FPRINTF (stderr, "%s", "Connected to ARM\n");
+ GNUNET_break (phase == 1);
+ phase++;
+ GNUNET_ARM_request_service_start (arm, "resolver", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, resolver_start_cb, NULL);
+ }
+ else
+ {
+ /* (7), ARM should stop (we disconnect from it) */
+ FPRINTF (stderr, "%s", "Disconnected from ARM\n");
+ GNUNET_break (phase == 7);
+ if (phase != 7)
+ ok = 3;
+ else if (ok == 1)
+ ok = 0;
+ GNUNET_SCHEDULER_add_now (trigger_disconnect, arm);
+ }
+}
+
+void
+srv_status (void *cls, const char *service, enum GNUNET_ARM_ServiceStatus status)
+{
+ FPRINTF (stderr, "Service %s is %u\n", service, status);
+ switch (phase)
+ {
+ default:
+ FPRINTF (stderr, "Unexpectedly got status %u for service %s\n", service);
+ GNUNET_break (0);
+ ok = 2;
#if START_ARM
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
+ GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, NULL, NULL);
#endif
- }
- GNUNET_ARM_start_service (arm, "resolver", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, &resolver_notify,
- NULL);
+ }
}
+static void
+arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
+{
+ /* (0) The request should be "sent" successfully
+ * ("sent", because it isn't going anywhere, ARM API starts ARM service
+ * by itself).
+ * ARM API should report that ARM service is starting.
+ */
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (phase == 0);
+ FPRINTF (stderr, "Sent 'START' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
+ GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
+ phase++;
+}
static void
task (void *cls, char *const *args, const char *cfgfile,
@@ -133,11 +200,13 @@ task (void *cls, char *const *args, const char *cfgfile,
else
GNUNET_free (armconfig);
}
- arm = GNUNET_ARM_connect (cfg, NULL);
+ arm = GNUNET_ARM_alloc (cfg);
+ GNUNET_ARM_connect (arm, arm_conn, NULL);
#if START_ARM
- GNUNET_ARM_start_service (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, &arm_notify, NULL);
+ GNUNET_ARM_request_service_start (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, arm_start_cb, NULL);
#else
- arm_notify (NULL, GNUNET_YES);
+ arm_start_cb (NULL, arm, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_STARTING);
+ arm_conn (NULL, GNUNET_YES, GNUNET_NO);
#endif
}
diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c
index 3395139eac..8a0dba1171 100644
--- a/src/arm/test_exponential_backoff.c
+++ b/src/arm/test_exponential_backoff.c
@@ -43,14 +43,20 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
static struct GNUNET_ARM_Handle *arm;
+static struct GNUNET_ARM_MonitorHandle *mon;
+
static int ok = 1;
+static int phase = 0;
+
static int trialCount;
static struct GNUNET_TIME_Absolute startedWaitingAt;
struct GNUNET_TIME_Relative waitedFor;
+struct GNUNET_TIME_Relative waitedFor_prev;
+
#if LOG_BACKOFF
static FILE *killLogFilePtr;
@@ -97,11 +103,8 @@ struct ShutdownContext
/**
* Handler receiving response to service shutdown requests.
- * First call with NULL: service misbehaving, or something.
- * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN:
- * - service will shutdown
- * Second call with NULL:
- * - service has now really shut down.
+ * We expect it to be called with NULL, since the service that
+ * we are shutting down will just die without replying.
*
* @param cls closure
* @param msg NULL, indicating socket closure.
@@ -111,7 +114,7 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
{
struct ShutdownContext *shutdown_ctx = cls;
- if (msg == NULL)
+ if (NULL == msg)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
if (shutdown_ctx->cont != NULL)
@@ -122,29 +125,7 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
GNUNET_free (shutdown_ctx);
return;
}
- GNUNET_assert (ntohs (msg->size) ==
- sizeof (struct GNUNET_MessageHeader));
- switch (ntohs (msg->type))
- {
- case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received confirmation for service shutdown.\n");
- shutdown_ctx->confirmed = GNUNET_YES;
- GNUNET_CLIENT_receive (shutdown_ctx->sock,
- &service_shutdown_handler, shutdown_ctx,
- GNUNET_TIME_UNIT_FOREVER_REL);
- break;
- default: /* Fall through */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Service shutdown refused!\n");
- if (shutdown_ctx->cont != NULL)
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES);
-
- GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
- break;
- }
+ GNUNET_assert (0);
}
@@ -183,25 +164,27 @@ write_shutdown (void *cls, size_t size, void *buf)
struct ShutdownContext *shutdown_ctx = cls;
if (size < sizeof (struct GNUNET_MessageHeader))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Failed to transmit shutdown request to client.\n"));
- shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
- GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
- GNUNET_free (shutdown_ctx);
- return 0; /* client disconnected */
- }
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Failed to transmit shutdown request to client.\n"));
+ FPRINTF (stderr, "%s", "Failed to send a shutdown request\n");
+ shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR);
+ GNUNET_CLIENT_disconnect (shutdown_ctx->sock);
+ GNUNET_free (shutdown_ctx);
+ return 0; /* client disconnected */
+ }
GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler,
shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
- shutdown_ctx->cancel_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
- (shutdown_ctx->timeout),
- &service_shutdown_cancel, shutdown_ctx);
+ shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (
+ GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout),
+ &service_shutdown_cancel, shutdown_ctx);
msg = (struct GNUNET_MessageHeader *) buf;
- msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
+ msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_STOP);
msg->size = htons (sizeof (struct GNUNET_MessageHeader));
- return sizeof (struct GNUNET_MessageHeader);
+ strcpy ((char *) &msg[1], "do-nothing");
+ FPRINTF (stderr, "%s", "Sent a shutdown request\n");
+ return sizeof (struct GNUNET_MessageHeader) + strlen ("do-nothing") + 1;
}
@@ -219,7 +202,7 @@ write_shutdown (void *cls, size_t size, void *buf)
*
*/
static void
-arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
+do_nothing_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
struct GNUNET_TIME_Relative timeout,
GNUNET_CLIENT_ShutdownTask cont, void *cont_cls)
{
@@ -231,125 +214,132 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
shutdown_ctx->sock = sock;
shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
GNUNET_CLIENT_notify_transmit_ready (sock,
- sizeof (struct GNUNET_MessageHeader),
+ sizeof (struct GNUNET_MessageHeader) + strlen ("do-nothing") + 1,
timeout, GNUNET_NO, &write_shutdown,
shutdown_ctx);
}
-
-static void
-arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus status)
-{
- GNUNET_assert ( (status == GNUNET_ARM_PROCESS_DOWN) ||
- (status == GNUNET_ARM_PROCESS_ALREADY_DOWN) );
-#if START_ARM
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL);
-#endif
-}
-
-
static void
kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
static void
-do_nothing_notify (void *cls, enum GNUNET_ARM_ProcessStatus status)
-{
- GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING);
- ok = 1;
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL);
-}
-
-static void
-arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus status)
+shutdown_cont (void *cls, int reason)
{
- GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING);
- GNUNET_ARM_start_service (arm, "do-nothing", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, TIMEOUT, &do_nothing_notify,
- NULL);
+ if (GNUNET_NO != reason)
+ {
+ /* Re-try shutdown */
+ FPRINTF (stderr, "%s", "do-nothing didn't die, trying again\n");
+ GNUNET_SCHEDULER_add_now (kill_task, NULL);
+ return;
+ }
+ startedWaitingAt = GNUNET_TIME_absolute_get ();
+ FPRINTF (stderr, "%s", "do-nothing is dead, starting the countdown\n");
}
-
static void
-kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-static void
-do_nothing_restarted_notify_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext
- *tc)
+kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- static char a;
-
- trialCount++;
+ static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL;
+ if (NULL != cbData)
+ {
+ waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
+ FPRINTF (stderr, "Waited for: %llu ms\n", waitedFor.rel_value);
#if LOG_BACKOFF
- if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
- {
- FPRINTF (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount);
- }
- else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0)
- {
- FPRINTF (killLogFilePtr, "%d.Reason is timeout!\n", trialCount);
- }
- else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0)
- {
- FPRINTF (killLogFilePtr, "%d.Service is running!\n", trialCount);
- }
+ FPRINTF (killLogFilePtr, "Waited for: %llu ms\n",
+ (unsigned long long) waitedFor.rel_value);
#endif
- GNUNET_SCHEDULER_add_now (&kill_task, &a);
+ }
+ else
+ {
+ waitedFor.rel_value = 0;
+ }
+ /* Connect to the doNothing task */
+ doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg);
+ GNUNET_assert (doNothingConnection != NULL);
+ if (trialCount == 12)
+ waitedFor_prev = waitedFor;
+ else if (trialCount == 13)
+ {
+ GNUNET_CLIENT_disconnect (doNothingConnection);
+ GNUNET_ARM_request_service_stop (arm, "do-nothing", TIMEOUT, NULL, NULL);
+ if (waitedFor_prev.rel_value >= waitedFor.rel_value)
+ ok = 9;
+ else
+ ok = 0;
+ trialCount += 1;
+ return;
+ }
+ trialCount += 1;
+ /* Use the created connection to kill the doNothingTask */
+ do_nothing_service_shutdown (doNothingConnection,
+ TIMEOUT, &shutdown_cont, NULL);
}
-
static void
-do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc)
+trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT,
- &do_nothing_restarted_notify_task, NULL);
+ GNUNET_ARM_disconnect (arm);
+ GNUNET_ARM_monitor_disconnect (mon);
}
static void
-shutdown_cont (void *cls, int reason)
+arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
{
- trialCount++;
- startedWaitingAt = GNUNET_TIME_absolute_get ();
- GNUNET_SCHEDULER_add_delayed (waitedFor, &do_test, NULL);
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING);
+ FPRINTF (stderr, "%s", "ARM service stopped\n");
+ GNUNET_SCHEDULER_add_now (trigger_disconnect, NULL);
}
-
-static void
-kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc)
+void
+srv_status (void *cls, struct GNUNET_ARM_MonitorHandle *mon, const char *service, enum GNUNET_ARM_ServiceStatus status)
{
- static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL;
-
- if (NULL != cbData)
- {
- waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt);
-
-#if LOG_BACKOFF
- FPRINTF (killLogFilePtr, "Waited for: %llu ms\n",
- (unsigned long long) waitedFor.rel_value);
-#endif
- }
- else
+ FPRINTF (stderr, "Service %s is %u, phase %u\n", service, status, phase);
+ if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
+ {
+ phase++;
+ GNUNET_ARM_request_service_start (arm, "do-nothing",
+ GNUNET_OS_INHERIT_STD_OUT_AND_ERR, TIMEOUT, NULL, NULL);
+ return;
+ }
+ if (phase == 1)
+ {
+ GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING);
+ GNUNET_break (0 == strcasecmp (service, "do-nothing"));
+ GNUNET_break (phase == 1);
+ FPRINTF (stderr, "%s", "do-nothing is starting\n");
+ phase++;
+ ok = 1;
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL);
+ }
+ else if ((phase == 2) && (strcasecmp ("do-nothing", service) == 0))
+ {
+ /* We passively monitor ARM for status updates. ARM should tell us
+ * when do-nothing dies (no need to run a service upness test ourselves).
+ */
+ if (status == GNUNET_ARM_SERVICE_STARTING)
{
- waitedFor.rel_value = 0;
+ FPRINTF (stderr, "%s", "do-nothing is starting\n");
+ GNUNET_SCHEDULER_add_now (kill_task, &ok);
}
- /* Connect to the doNothing task */
- doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg);
- GNUNET_assert (doNothingConnection != NULL);
- if (trialCount == 12)
+ else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14))
{
- GNUNET_CLIENT_disconnect (doNothingConnection);
- GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop,
- NULL);
- ok = 0;
- return;
+ phase++;
+ GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL);
}
- /* Use the created connection to kill the doNothingTask */
- arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL);
+ }
}
+static void
+arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
+{
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
+ GNUNET_break (phase == 0);
+ FPRINTF (stderr, "Sent 'START' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully");
+}
static void
task (void *cls, char *const *args, const char *cfgfile,
@@ -359,9 +349,8 @@ task (void *cls, char *const *args, const char *cfgfile,
cfg = c;
if (NULL != cfgfile)
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG",
- &armconfig))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "arm",
+ "CONFIG", &armconfig))
{
GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle
*) cfg, "arm", "CONFIG",
@@ -371,16 +360,18 @@ task (void *cls, char *const *args, const char *cfgfile,
GNUNET_free (armconfig);
}
- arm = GNUNET_ARM_connect (cfg, NULL);
+ arm = GNUNET_ARM_alloc (cfg);
+ GNUNET_ARM_connect (arm, NULL, NULL);
+ mon = GNUNET_ARM_monitor_alloc (cfg);
+ GNUNET_ARM_monitor (mon, srv_status, NULL);
#if START_ARM
- GNUNET_ARM_start_service (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_TIME_UNIT_ZERO, &arm_notify,
- NULL);
+ GNUNET_ARM_request_service_start (arm, "arm",
+ GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_TIME_UNIT_ZERO, arm_start_cb, NULL);
#else
- arm_do_nothing (NULL, GNUNET_YES);
+ arm_start_cb (NULL, arm, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_SERVICE_STARTING);
#endif
}
-
static int
check ()
{
diff --git a/src/arm/test_gnunet_service_arm.c b/src/arm/test_gnunet_service_arm.c
index 9e9286ac1c..bd7fe5fa95 100644
--- a/src/arm/test_gnunet_service_arm.c
+++ b/src/arm/test_gnunet_service_arm.c
@@ -42,23 +42,22 @@ static int ret = 1;
static struct GNUNET_ARM_Handle *arm;
-
static void
-arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success)
+trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- if (success != GNUNET_ARM_PROCESS_DOWN)
- {
- GNUNET_break (0);
- ret = 4;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n");
- }
GNUNET_ARM_disconnect (arm);
arm = NULL;
}
+static void
+arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
+{
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING);
+ if (result != GNUNET_ARM_RESULT_STOPPING)
+ ret = 4;
+ GNUNET_SCHEDULER_add_now (trigger_disconnect, NULL);
+}
static void
hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen)
@@ -66,43 +65,37 @@ hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen)
if ((ret == 0) || (ret == 4))
return;
if (NULL == addr)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n");
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
- ret = 3;
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Resolved hostname, now stopping ARM\n");
- ret = 0;
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n");
+ ret = 3;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Resolved hostname, now stopping ARM\n");
+ ret = 0;
+ }
+ GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL);
}
-
static void
-arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success)
+arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result)
{
- if (success != GNUNET_ARM_PROCESS_STARTING)
- {
- GNUNET_break (0);
- ret = 1;
- return;
- }
+ GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK);
+ GNUNET_break (result == GNUNET_ARM_RESULT_STARTING);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to resolve our own hostname!\n");
+ "Trying to resolve our own hostname!\n");
/* connect to the resolver service */
- if (NULL ==
- GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT,
- &hostNameResolveCB, NULL))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unable initiate connection to resolver service\n");
- ret = 2;
- GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL);
- }
+ if (NULL == GNUNET_RESOLVER_hostname_resolve (
+ AF_UNSPEC, TIMEOUT, &hostNameResolveCB, NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unable initiate connection to resolver service\n");
+ ret = 2;
+ GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL);
+ }
}
-
static void
run (void *cls, char *const *args, const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *c)
@@ -122,10 +115,10 @@ run (void *cls, char *const *args, const char *cfgfile,
else
GNUNET_free (armconfig);
}
- arm = GNUNET_ARM_connect (c, NULL);
- GNUNET_ARM_start_service (arm, "arm",
- GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT,
- &arm_notify, NULL);
+ arm = GNUNET_ARM_alloc (c);
+ GNUNET_ARM_connect (arm, NULL, NULL);
+ GNUNET_ARM_request_service_start (arm, "arm",
+ GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, arm_start_cb, NULL);
}
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h
index 0aa916bd46..be46831a41 100644
--- a/src/include/gnunet_arm_service.h
+++ b/src/include/gnunet_arm_service.h
@@ -43,112 +43,208 @@ extern "C"
/**
* Version of the arm API.
*/
-#define GNUNET_ARM_VERSION 0x00000001
+#define GNUNET_ARM_VERSION 0x00000002
/**
- * Values characterizing GNUnet process states.
+ * Statuses of the requests that client can send to ARM.
*/
-enum GNUNET_ARM_ProcessStatus
+enum GNUNET_ARM_RequestStatus
{
/**
- * Service name is unknown to ARM.
+ * Message was sent successfully.
*/
- GNUNET_ARM_PROCESS_UNKNOWN = -1,
+ GNUNET_ARM_REQUEST_SENT_OK = 0,
/**
- * Service is now down (due to client request).
+ * Misconfiguration (can't connect to the ARM service).
*/
- GNUNET_ARM_PROCESS_DOWN = 0,
+ GNUNET_ARM_REQUEST_CONFIGURATION_ERROR = 1,
/**
- * Service is already running.
+ * We disconnected from ARM, and request was not sent.
*/
- GNUNET_ARM_PROCESS_ALREADY_RUNNING = 1,
+ GNUNET_ARM_REQUEST_DISCONNECTED = 2,
/**
- * Service is currently being started (due to client request).
+ * ARM API is busy (probably trying to connect to ARM),
+ * and request was not sent. Try again later.
*/
- GNUNET_ARM_PROCESS_STARTING = 2,
-
+ GNUNET_ARM_REQUEST_BUSY = 3,
+
/**
- * Service is already being stopped by some other client.
+ * It was discovered that the request would be too long to fit in a message,
+ * and thus it was not sent.
*/
- GNUNET_ARM_PROCESS_ALREADY_STOPPING = 3,
+ GNUNET_ARM_REQUEST_TOO_LONG = 4,
/**
- * Service is already down (no action taken)
+ * Request time ran out before we had a chance to send it.
*/
- GNUNET_ARM_PROCESS_ALREADY_DOWN = 4,
+ GNUNET_ARM_REQUEST_TIMEOUT = 5
+
+};
+
+/**
+ * Statuses of services.
+ */
+enum GNUNET_ARM_ServiceStatus
+{
/**
- * ARM is currently being shut down (no more process starts)
+ * Dummy message.
*/
- GNUNET_ARM_PROCESS_SHUTDOWN = 5,
+ GNUNET_ARM_SERVICE_MONITORING_STARTED = 0,
/**
- * Error in communication with ARM
+ * Service was stopped.
*/
- GNUNET_ARM_PROCESS_COMMUNICATION_ERROR = 6,
+ GNUNET_ARM_SERVICE_STOPPED = 1,
/**
- * Timeout in communication with ARM
+ * Service starting was initiated
*/
- GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT = 7,
+ GNUNET_ARM_SERVICE_STARTING = 2,
/**
- * Failure to perform operation
+ * Service stopping was initiated
*/
- GNUNET_ARM_PROCESS_FAILURE = 8
+ GNUNET_ARM_SERVICE_STOPPING = 3
};
+/**
+ * Replies to ARM requests
+ */
+enum GNUNET_ARM_Result
+{
+ /**
+ * Service was stopped (never sent for ARM itself).
+ */
+ GNUNET_ARM_RESULT_STOPPED = 0,
+
+ /**
+ * ARM stopping was initiated (there's no "stopped" for ARM itself).
+ */
+ GNUNET_ARM_RESULT_STOPPING = 1,
+
+ /**
+ * Service starting was initiated
+ */
+ GNUNET_ARM_RESULT_STARTING = 2,
+
+ /**
+ * Asked to start it, but it's already starting.
+ */
+ GNUNET_ARM_RESULT_IS_STARTING_ALREADY = 3,
+
+ /**
+ * Asked to stop it, but it's already stopping.
+ */
+ GNUNET_ARM_RESULT_IS_STOPPING_ALREADY = 4,
+
+ /**
+ * Asked to start it, but it's already started.
+ */
+ GNUNET_ARM_RESULT_IS_STARTED_ALREADY = 5,
+
+ /**
+ * Asked to stop it, but it's already stopped.
+ */
+ GNUNET_ARM_RESULT_IS_STOPPED_ALREADY = 6,
+
+ /**
+ * Asked to start or stop a service, but it's not known.
+ */
+ GNUNET_ARM_RESULT_IS_NOT_KNOWN = 7,
+
+ /**
+ * Tried to start a service, but that failed for some reason.
+ */
+ GNUNET_ARM_RESULT_START_FAILED = 8,
+
+ /**
+ * Asked to start something, but ARM is shutting down and can't comply.
+ */
+ GNUNET_ARM_RESULT_IN_SHUTDOWN = 9
+};
+
+
+/**
+ * Handle for interacting with ARM.
+ */
+struct GNUNET_ARM_Handle;
+
/**
- * Callback function invoked when operation is complete.
+ * Function called whenever we connect to or disconnect from ARM.
*
* @param cls closure
- * @param result outcome of the operation
+ * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected
+ * @param error GNUNET_YES if we encountered a permanent error, and there
+ * will be no re-connection.
*/
-typedef void (*GNUNET_ARM_Callback) (void *cls,
- enum GNUNET_ARM_ProcessStatus result);
+typedef void (*GNUNET_ARM_ConnectionStatusCallback) (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error);
+
/**
- * Callback function invoked when list operation is complete.
+ * Function called in response to a start/stop request.
+ * Will be called when request was not sent successfully,
+ * or when a reply comes. If the request was not sent successfully,
+ * 'rs' will indicate that, and 'service' and 'result' will be undefined.
*
* @param cls closure
- * @param result outcome of the operation (GNUNET_YES if successful)
- * @param count number of strings in the list
- * @param list list of running services
+ * @param arm handle to the arm connection
+ * @param rs status of the request
+ * @param service service name
+ * @param result result of the operation
*/
-typedef void (*GNUNET_ARM_List_Callback) (void *cls,
- int result,
- unsigned int count,
- const char *const *list);
+typedef void (*GNUNET_ARM_ResultCallback) (void *cls, struct GNUNET_ARM_Handle *arm, enum GNUNET_ARM_RequestStatus rs, const char *service, enum GNUNET_ARM_Result result);
/**
- * Handle for interacting with ARM.
+ * Callback function invoked when list operation is complete.
+ * Will be called when request was not sent successfully,
+ * or when a reply comes. If the request was not sent successfully,
+ * 'rs' will indicate that, and 'count' and 'list' will be undefined.
+ *
+ * @param cls closure
+ * @param arm handle to the arm connection
+ * @param rs status of the request
+ * @param count number of strings in the list
+ * @param list list of running services
*/
-struct GNUNET_ARM_Handle;
+typedef void (*GNUNET_ARM_ServiceListCallback) (void *cls, struct GNUNET_ARM_Handle *arm, enum GNUNET_ARM_RequestStatus rs, unsigned int count, const char *const*list);
/**
* Setup a context for communicating with ARM. Note that this
* can be done even if the ARM service is not yet running.
+ * Never fails.
*
* @param cfg configuration to use (needed to contact ARM;
* the ARM service may internally use a different
* configuration to determine how to start the service).
- * @param service service that *this* process is implementing/providing, can be NULL
- * @return context to use for further ARM operations, NULL on error
+ * @return context to use for further ARM operations
*/
struct GNUNET_ARM_Handle *
-GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *service);
+GNUNET_ARM_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+/**
+ * Start connecting to the ARM service using the context.
+ * @param conn_status called when we (dis)connect from/to ARM.
+ * It's also called on connection errors.
+ * @param cls closure for conn_status
+ *
+ * @param h ARM handle
+ */
+void
+GNUNET_ARM_connect (struct GNUNET_ARM_Handle *h,
+ GNUNET_ARM_ConnectionStatusCallback conn_status, void *cls);
/**
- * Disconnect from the ARM service.
+ * Disconnect from the ARM service and destroy the handle.
+ * Don't call this from inside an ARM callback!
*
* @param h the handle that was being used
*/
@@ -157,60 +253,107 @@ GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h);
/**
- * Start a service. Note that this function merely asks ARM to start
- * the service and that ARM merely confirms that it forked the
- * respective process. The specified callback may thus return before
- * the service has started to listen on the server socket and it may
- * also be that the service has crashed in the meantime. Clients
- * should repeatedly try to connect to the service at the respective
- * port (with some delays in between) before assuming that the service
- * actually failed to start. Note that if an error is returned to the
- * callback, clients obviously should not bother with trying to
- * contact the service.
+ * Request a list of running services.
*
* @param h handle to ARM
- * @param service_name name of the service
- * @param std_inheritance flags controlling std descriptors inheritance
* @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
+ * @param cont callback to invoke after request is sent or is not sent
+ * @param cont_cls closure for callback
*/
void
-GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name,
- enum GNUNET_OS_InheritStdioFlags std_inheritance,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_Callback cb, void *cb_cls);
+GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_ServiceListCallback cont, void *cont_cls);
/**
- * Stop a service. Note that the callback is invoked as soon
- * as ARM confirms that it will ask the service to terminate.
- * The actual termination may still take some time.
+ * Request a service to be stopped.
+ * Stopping arm itself will not invalidate its handle, and
+ * ARM API will try to restore connection to the ARM service,
+ * even if ARM connection was lost because you asked for ARM to be stopped.
+ * Call GNUNET_ARM_disconnect () to free the handle and prevent
+ * further connection attempts.
*
* @param h handle to ARM
* @param service_name name of the service
* @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
+ * @param cont callback to invoke after request is sent or is not sent
+ * @param cont_cls closure for callback
*/
void
-GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_Callback cb, void *cb_cls);
+GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h,
+ const char *service_name, struct GNUNET_TIME_Relative timeout,
+ GNUNET_ARM_ResultCallback cont, void *cont_cls);
/**
- * List all running services.
- *
+ * Request for a service to be started.
+ *
* @param h handle to ARM
+ * @param service_name name of the service
+ * @param std_inheritance inheritance of std streams
* @param timeout how long to wait before failing for good
- * @param cb callback to invoke when service is ready
- * @param cb_cls closure for callback
+ * @param cont callback to invoke after request is sent or not sent
+ * @param cont_cls closure for callback
*/
void
-GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h,
- struct GNUNET_TIME_Relative timeout,
- GNUNET_ARM_List_Callback cb, void *cb_cls);
+GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h,
+ const char *service_name, enum GNUNET_OS_InheritStdioFlags std_inheritance,
+ struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cont,
+ void *cont_cls);
+
+
+/**
+ * Handle for monitoring ARM.
+ */
+struct GNUNET_ARM_MonitorHandle;
+
+
+/**
+ * Function called in when a status update arrives.
+ *
+ * @param cls closure
+ * @param arm handle to the arm connection
+ * @param service service name
+ * @param status status of the service
+ */
+typedef void (*GNUNET_ARM_ServiceStatusCallback) (void *cls, struct GNUNET_ARM_MonitorHandle *arm, const char *service, enum GNUNET_ARM_ServiceStatus status);
+
+
+/**
+ * Setup a context for monitoring ARM. Note that this
+ * can be done even if the ARM service is not yet running.
+ * Never fails.
+ *
+ * @param cfg configuration to use (needed to contact ARM;
+ * the ARM service may internally use a different
+ * configuration to determine how to start the service).
+ * @return context to use for further ARM monitor operations
+ */
+struct GNUNET_ARM_MonitorHandle *
+GNUNET_ARM_monitor_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+/**
+ * Start connecting to the ARM service for monitoring using the context.
+ *
+ * @param h ARM monitor handle
+ * @param cont callback to invoke on status updates
+ * @param cont_cls closure
+ */
+void
+GNUNET_ARM_monitor (struct GNUNET_ARM_MonitorHandle *h,
+ GNUNET_ARM_ServiceStatusCallback cont, void *cont_cls);
+
+
+/**
+ * Disconnect from the ARM service and destroy the handle.
+ * Don't call this from inside an ARM callback!
+ *
+ * @param h the handle that was being used
+ */
+void
+GNUNET_ARM_monitor_disconnect (struct GNUNET_ARM_MonitorHandle *h);
+
#if 0 /* keep Emacsens' auto-indent happy */
{
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 222924cf86..9d65c66c2f 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -78,14 +78,14 @@ extern "C"
#define GNUNET_MESSAGE_TYPE_ARM_STOP 9
/**
- * Request ARM service itself to shutdown.
+ * Response from ARM.
*/
-#define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 10
+#define GNUNET_MESSAGE_TYPE_ARM_RESULT 10
/**
- * Response from ARM.
+ * Status update from ARM.
*/
-#define GNUNET_MESSAGE_TYPE_ARM_RESULT 11
+#define GNUNET_MESSAGE_TYPE_ARM_STATUS 11
/**
* Request to ARM to list all currently running services
@@ -97,6 +97,11 @@ extern "C"
*/
#define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT 13
+/**
+ * Request to ARM to notify client of service status changes
+ */
+#define GNUNET_MESSAGE_TYPE_ARM_MONITOR 14
+
/*******************************************************************************
* HELLO message types
******************************************************************************/
diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h
index f59e97015f..f7b5264162 100644
--- a/src/include/gnunet_server_lib.h
+++ b/src/include/gnunet_server_lib.h
@@ -395,6 +395,17 @@ typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls,
struct GNUNET_SERVER_Client *
client);
+/**
+ * Functions with this signature are called whenever a client
+ * is connected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+typedef void (*GNUNET_SERVER_ConnectCallback) (void *cls,
+ struct GNUNET_SERVER_Client *client);
+
+
/**
* Ask the server to notify us whenever a client disconnects.
@@ -417,6 +428,20 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
/**
+ * Ask the server to notify us whenever a client connects.
+ * This function is called whenever the actual network connection
+ * is opened.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on sconnect
+ * @param callback_cls closure for callback
+ */
+void
+GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback, void *callback_cls);
+
+
+/**
* Ask the server to stop notifying us whenever a client disconnects.
*
* @param server the server manageing the clients
@@ -430,6 +455,18 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
/**
+ * Ask the server to stop notifying us whenever a client connects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on connect
+ * @param callback_cls closure for callback
+ */
+void
+GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback, void *callback_cls);
+
+
+/**
* Ask the server to disconnect from the given client.
* This is the same as returning GNUNET_SYSERR from a message
* handler, except that it allows dropping of a client even
diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c
index 0c104fab48..303f1fffc7 100644
--- a/src/regex/gnunet-regex-profiler.c
+++ b/src/regex/gnunet-regex-profiler.c
@@ -997,6 +997,17 @@ find_next_string (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
}
+
+/**
+ * Start announcing the next regex in the DHT.
+ *
+ * @param cls Index of the next peer in the peers array.
+ * @param tc TaskContext.
+ */
+void
+announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
/**
* ARM connect adapter. Opens a connection to the ARM service.
*
@@ -1010,7 +1021,8 @@ arm_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct RegexPeer *peer = cls;
- peer->arm_handle = GNUNET_ARM_connect (cfg, NULL);
+ peer->arm_handle = GNUNET_ARM_alloc (cfg);
+ GNUNET_ARM_connect (peer->arm_handle, NULL, NULL);
return peer->arm_handle;
}
@@ -1036,104 +1048,52 @@ arm_da (void *cls, void *op_result)
}
}
-
-/**
- * Start announcing the next regex in the DHT.
- *
- * @param cls Index of the next peer in the peers array.
- * @param tc TaskContext.
- */
-void
-announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-
-/**
- * Callback function invoked when ARM peration is complete: deamon is started.
- *
- * @param cls Closure (RegexPeer).
- * @param result Outcome of the operation.
- */
static void
-arm_start_cb (void *cls, enum GNUNET_ARM_ProcessStatus result)
+regexprofiler_start_cb (void *cls, struct GNUNET_ARM_Handle *arm,
+ enum GNUNET_ARM_RequestStatus rs, const char *service,
+ enum GNUNET_ARM_Result result)
{
struct RegexPeer *peer = (struct RegexPeer *) cls;
- static unsigned int peer_cnt;
unsigned int next_p;
- switch (result)
+ if (rs != GNUNET_ARM_REQUEST_SENT_OK)
{
- /**
- * Service is currently being started (due to client request).
- */
- case GNUNET_ARM_PROCESS_STARTING:
- GNUNET_TESTBED_operation_done (peer->op_handle);
- peer->op_handle = NULL;
-
- if (peer_cnt < (num_peers - 1))
- {
- next_p = (++peer_cnt % num_peers);
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
- GNUNET_TIME_UNIT_MILLISECONDS,
- 400),
- &announce_next_regex,
- (void *) (long) next_p);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "All daemons started."
- " Waiting %s to start string searches\n",
- GNUNET_STRINGS_relative_time_to_string (search_delay,
- GNUNET_NO));
- GNUNET_SCHEDULER_add_delayed (search_delay,
- do_connect_by_string,
- NULL);
- }
- break;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM request was not sent: %u\n", rs);
+ GNUNET_abort ();
+ }
+ else if (result != GNUNET_ARM_RESULT_STARTING)
+ {
+ /* FIXME: maybe check for other acceptable results (already starting,
+ * already started)?
+ */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM failed to start regexprofiler: %u\n", result);
+ GNUNET_abort ();
+ }
+ GNUNET_TESTBED_operation_done (peer->op_handle);
+ peer->op_handle = NULL;
- /**
- * Service name is unknown to ARM.
- */
- case GNUNET_ARM_PROCESS_UNKNOWN:
- /**
- * Service is now down (due to client request).
- */
- case GNUNET_ARM_PROCESS_DOWN:
- /**
- * Service is already running.
- */
- case GNUNET_ARM_PROCESS_ALREADY_RUNNING:
- /**
- * Service is already being stopped by some other client.
- */
- case GNUNET_ARM_PROCESS_ALREADY_STOPPING:
- /**
- * Service is already down (no action taken)
- */
- case GNUNET_ARM_PROCESS_ALREADY_DOWN:
- /**
- * ARM is currently being shut down (no more process starts)
- */
- case GNUNET_ARM_PROCESS_SHUTDOWN:
- /**
- * Error in communication with ARM
- */
- case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR:
- /**
- * Timeout in communication with ARM
- */
- case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT:
- /**
- * Failure to perform operation
- */
- case GNUNET_ARM_PROCESS_FAILURE:
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM returned %d\n", result);
- GNUNET_abort ();
+ if (peer_cnt < (num_peers - 1))
+ {
+ next_p = (++peer_cnt % num_peers);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
+ GNUNET_TIME_UNIT_MILLISECONDS,
+ 400),
+ &announce_next_regex,
+ (void *) (long) next_p);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "All daemons started."
+ " Waiting %s to start string searches\n",
+ GNUNET_STRINGS_relative_time_to_string (search_delay,
+ GNUNET_NO));
+ GNUNET_SCHEDULER_add_delayed (search_delay,
+ do_connect_by_string,
+ NULL);
}
}
-
/**
* ARM connect callback. Called when we are connected to the arm service for
* the peer in 'cls'. If successfull we start the regex deamon to start
@@ -1160,11 +1120,10 @@ arm_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
GNUNET_assert (peer->op_handle == op);
GNUNET_assert (peer->arm_handle == ca_result);
- GNUNET_ARM_start_service (ca_result, "regexprofiler",
- GNUNET_OS_INHERIT_STD_NONE,
- GNUNET_TIME_UNIT_FOREVER_REL,
- &arm_start_cb,
- peer);
+ GNUNET_ARM_request_service_start (ca_result, "regexprofiler",
+ GNUNET_OS_INHERIT_STD_NONE,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ regexprofiler_start_cb, cls);
}
diff --git a/src/regex/regex_test_lib.c b/src/regex/regex_test_lib.c
index 57c6b13e88..56ccb34968 100644
--- a/src/regex/regex_test_lib.c
+++ b/src/regex/regex_test_lib.c
@@ -267,7 +267,7 @@ GNUNET_REGEX_read_from_file (const char *filename)
struct GNUNET_DISK_FileHandle *f;
unsigned int nr;
unsigned int offset;
- off_t size;
+ uint64_t size;
size_t len;
char *buffer;
char *regex;
diff --git a/src/util/client.c b/src/util/client.c
index 69380c9b03..8b4776201e 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -1007,6 +1007,7 @@ client_notify (void *cls, size_t size, void *buf)
size_t ret;
struct GNUNET_TIME_Relative delay;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "client_notify is running\n");
th->th = NULL;
client->th = NULL;
if (NULL == buf)
diff --git a/src/util/connection.c b/src/util/connection.c
index c4795cebe8..ea35b04e1d 100644
--- a/src/util/connection.c
+++ b/src/util/connection.c
@@ -1153,14 +1153,22 @@ process_notify (struct GNUNET_CONNECTION_Handle *connection)
size_t size;
GNUNET_CONNECTION_TransmitReadyNotify notify;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "process_notify is running\n");
+
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task);
if (NULL == (notify = connection->nth.notify_ready))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Noone to notify\n");
return GNUNET_NO;
+ }
used = connection->write_buffer_off - connection->write_buffer_pos;
avail = connection->write_buffer_size - used;
size = connection->nth.notify_size;
if (size > avail)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough buffer\n");
return GNUNET_NO;
+ }
connection->nth.notify_ready = NULL;
if (connection->write_buffer_size - connection->write_buffer_off < size)
{
diff --git a/src/util/server.c b/src/util/server.c
index fc5f263bf8..5268214779 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -111,6 +111,16 @@ struct GNUNET_SERVER_Handle
struct NotifyList *disconnect_notify_list_tail;
/**
+ * Head of linked list of functions to call on connects by clients.
+ */
+ struct NotifyList *connect_notify_list_head;
+
+ /**
+ * Tail of linked list of functions to call on connects by clients.
+ */
+ struct NotifyList *connect_notify_list_tail;
+
+ /**
* Function to call for access control.
*/
GNUNET_CONNECTION_AccessCheck access;
@@ -756,6 +766,14 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
npos);
GNUNET_free (npos);
}
+ while (NULL != (npos = server->connect_notify_list_head))
+ {
+ npos->callback (npos->callback_cls, NULL);
+ GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ npos);
+ GNUNET_free (npos);
+ }
GNUNET_free (server);
}
@@ -1161,6 +1179,7 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
struct GNUNET_CONNECTION_Handle *connection)
{
struct GNUNET_SERVER_Client *client;
+ struct NotifyList *n;
client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client));
client->connection = connection;
@@ -1178,6 +1197,9 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
client->mst =
GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server);
GNUNET_assert (NULL != client->mst);
+ for (n = server->connect_notify_list_head; NULL != n; n = n->next)
+ n->callback (n->callback_cls, client);
+
client->receive_pending = GNUNET_YES;
GNUNET_CONNECTION_receive (client->connection,
GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
@@ -1277,10 +1299,34 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
/**
- * Ask the server to stop notifying us whenever a client disconnects.
+ * Ask the server to notify us whenever a client connects.
+ * This function is called whenever the actual network connection
+ * is opened.
*
* @param server the server manageing the clients
- * @param callback function to call on disconnect
+ * @param callback function to call on sconnect
+ * @param callback_cls closure for callback
+ */
+void
+GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback, void *callback_cls)
+{
+ struct NotifyList *n;
+
+ n = GNUNET_malloc (sizeof (struct NotifyList));
+ n->callback = callback;
+ n->callback_cls = callback_cls;
+ GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ n);
+}
+
+
+/**
+ * Ask the server to stop notifying us whenever a client connects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on connect
* @param callback_cls closure for callback
*/
void
@@ -1306,6 +1352,34 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
/**
+ * Ask the server to stop notifying us whenever a client disconnects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on disconnect
+ * @param callback_cls closure for callback
+ */
+void
+GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+ GNUNET_SERVER_ConnectCallback callback, void *callback_cls)
+{
+ struct NotifyList *pos;
+
+ for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
+ if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
+ break;
+ if (NULL == pos)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+ server->connect_notify_list_tail,
+ pos);
+ GNUNET_free (pos);
+}
+
+
+/**
* Destroy the connection that is passed in via 'cls'. Used
* as calling 'GNUNET_CONNECTION_destroy' from within a function
* that was itself called from within 'process_notify' of