-extending defaults
[oweals/gnunet.git] / src / arm / arm_api.c
index 0f4ae6a4f0bf70934b1529813cc4e9f4d7f19c16..c352cbdae2beca55b34e973569ecae5cff416c70 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+     (C) 2009, 2010, 2012 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
@@ -52,7 +52,6 @@ struct GNUNET_ARM_Handle
 
 };
 
-
 /**
  * Context for handling the shutdown of a service.
  */
@@ -83,6 +82,11 @@ struct ShutdownContext
    */
   void *cont_cls;
 
+  /**
+   * Handle for transmission request.
+   */
+  struct GNUNET_CLIENT_TransmitHandle *th;
+
   /**
    * Result of the operation
    */
@@ -178,9 +182,10 @@ service_shutdown_cancel (void *cls,
 static size_t
 write_shutdown (void *cls, size_t size, void *buf)
 {
-  struct GNUNET_MessageHeader *msg;
   struct ShutdownContext *shutdown_ctx = cls;
+  struct GNUNET_MessageHeader *msg;
 
+  shutdown_ctx->th = NULL;
   if (size < sizeof (struct GNUNET_MessageHeader))
     {
       LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -230,11 +235,10 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
   shutdown_ctx->sock = sock;
   shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   shutdown_ctx->confirmed = GNUNET_ARM_PROCESS_COMMUNICATION_ERROR;    
-  /* FIXME: store return value? */
-  GNUNET_CLIENT_notify_transmit_ready (sock,
-                                      sizeof (struct GNUNET_MessageHeader),
-                                      timeout, GNUNET_YES, &write_shutdown,
-                                      shutdown_ctx);
+  shutdown_ctx->th = GNUNET_CLIENT_notify_transmit_ready (sock,
+                                                         sizeof (struct GNUNET_MessageHeader),
+                                                         timeout, GNUNET_NO, &write_shutdown,
+                                                         shutdown_ctx);
 }
 
 
@@ -678,4 +682,166 @@ GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
 }
 
 
+/**
+ * Internal state for a list request with ARM.
+ */
+struct ListRequestContext
+{
+
+  /**
+   * 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;
+
+  /**
+   * Closure for "callback".
+   */
+  void *cls;
+
+  /**
+   * Timeout for the operation.
+   */
+  struct GNUNET_TIME_Absolute timeout;
+};
+
+
+/**
+ * Process a response from ARM for the list request.
+ *
+ * @param cls the list request context
+ * @param msg the response
+ */
+static void
+handle_list_response (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+  struct ListRequestContext *sc = cls;
+  const struct GNUNET_ARM_ListResultMessage *res;
+  const char *pos;
+  uint16_t size_check;
+  uint16_t rcount;
+  uint16_t msize;
+  
+  if (NULL == msg)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+        "Error receiving response to LIST request from ARM\n");
+    GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO);
+    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);
+    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) )
+  {
+    GNUNET_break (0);
+    sc->callback (sc->cls, GNUNET_NO, 0, NULL);
+    GNUNET_free (sc);
+    return;
+  }
+  size_check = 0;
+  res = (const struct GNUNET_ARM_ListResultMessage *) msg;
+  rcount = ntohs (res->count);
+  {
+    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);
+  }
+  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)
+    {
+      client = GNUNET_CLIENT_connect ("arm", h->cfg);
+      if (client == NULL)
+        {
+          LOG (GNUNET_ERROR_TYPE_DEBUG,
+               "arm_api, GNUNET_CLIENT_connect returned NULL\n");
+          cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL);
+          return;
+        }
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
+      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: %llu ms\n", 
+       (unsigned long long)timeout.rel_value);
+  
+    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))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, 
+           "Error while trying to transmit request to list services to ARM\n");
+      if (cb != NULL)
+        cb (cb_cls, GNUNET_SYSERR, 0, NULL);
+      GNUNET_free (sctx);
+      return;
+    }
+}
+
 /* end of arm_api.c */