fix
[oweals/gnunet.git] / src / core / core_api.c
index 4af9aebfdba367bfb18149c2b41654f728e1dbb3..c21be318a4ffac0fd5fcee4480fd523b36340e1d 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
+     (C) 2009, 2010 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
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -25,6 +25,7 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
+#include "gnunet_constants.h"
 #include "gnunet_core_service.h"
 #include "core.h"
 
@@ -65,6 +66,11 @@ struct GNUNET_CORE_Handle
    */
   GNUNET_CORE_DisconnectEventHandler disconnects;
 
+  /**
+   * Function to call whenever we're notified about a peer changing status.
+   */  
+  GNUNET_CORE_PeerStatusEventHandler status_events;
+  
   /**
    * Function to call whenever we receive an inbound message.
    */
@@ -250,6 +256,10 @@ static size_t transmit_start (void *cls, size_t size, void *buf);
 static void
 reconnect (struct GNUNET_CORE_Handle *h)
 {
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Reconnecting to CORE service\n");
+#endif
   if (h->client_notifications != NULL)
     GNUNET_CLIENT_disconnect (h->client_notifications, GNUNET_NO);
   h->currently_down = GNUNET_YES;
@@ -277,11 +287,16 @@ reconnect (struct GNUNET_CORE_Handle *h)
  * @param tc context, can be NULL (!)
  */
 static void
-timeout_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+timeout_request (void *cls, 
+                const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_CORE_TransmitHandle *th = cls;
 
   th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Signalling timeout of request for transmission to CORE service\n");
+#endif
   GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL));
 }
 
@@ -302,8 +317,10 @@ request_start (void *cls, size_t size, void *buf)
   struct GNUNET_CORE_TransmitHandle *th;
   size_t ret;
 
-  h->cth = NULL;
+  h->cth = NULL;  
   th = h->pending_head;
+  if (th == NULL)
+    return 0;
   if (buf == NULL)
     {
       timeout_request (th, NULL);
@@ -317,6 +334,11 @@ request_start (void *cls, size_t size, void *buf)
   GNUNET_assert (size >= th->msize);
   ret = th->get_message (th->get_message_cls, size, buf);
   GNUNET_assert (ret <= size);
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Transmitting %u bytes to core\n",
+             ret);
+#endif
   return ret;
 }
 
@@ -366,6 +388,7 @@ main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
   const struct DisconnectNotifyMessage *dnm;
   const struct NotifyTrafficMessage *ntm;
   const struct GNUNET_MessageHeader *em;
+  const struct PeerStatusNotifyMessage *psnm;
   uint16_t msize;
   uint16_t et;
   const struct GNUNET_CORE_MessageHandler *mh;
@@ -418,6 +441,26 @@ main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
       h->disconnects (h->cls,
                      &dnm->peer);
       break;
+    case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE:
+      if (NULL == h->status_events)
+        {
+          GNUNET_break (0);
+          break;
+        }
+      if (msize != sizeof (struct PeerStatusNotifyMessage))
+        {
+          GNUNET_break (0);
+          break;
+        }
+      psnm = (const struct PeerStatusNotifyMessage *) msg;
+      h->status_events (h->cls,
+                       &psnm->peer,
+                       GNUNET_TIME_relative_ntoh (psnm->latency),
+                       ntohl (psnm->distance),
+                       psnm->bandwidth_in,
+                       psnm->bandwidth_out,
+                       GNUNET_TIME_absolute_ntoh (psnm->timeout));
+      break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
       if (msize <
           sizeof (struct NotifyTrafficMessage) +
@@ -643,6 +686,8 @@ transmit_start (void *cls, size_t size, void *buf)
     opt |= GNUNET_CORE_OPTION_SEND_CONNECT;
   if (h->disconnects != NULL)
     opt |= GNUNET_CORE_OPTION_SEND_DISCONNECT;
+  if (h->status_events != NULL)
+    opt |= GNUNET_CORE_OPTION_SEND_STATUS_CHANGE;
   if (h->inbound_notify != NULL)
     {
       if (h->inbound_hdr_only)
@@ -682,6 +727,7 @@ transmit_start (void *cls, size_t size, void *buf)
  *        connected to the core service; note that timeout is only meaningful if init is not NULL
  * @param connects function to call on peer connect, can be NULL
  * @param disconnects function to call on peer disconnect / timeout, can be NULL
+ * @param status_events function to call on changes to peer connection status, can be NULL
  * @param inbound_notify function to call for all inbound messages, can be NULL
  * @param inbound_hdr_only set to GNUNET_YES if inbound_notify will only read the
  *                GNUNET_MessageHeader and hence we do not need to give it the full message;
@@ -702,6 +748,7 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
                      GNUNET_CORE_StartupCallback init,
                      GNUNET_CORE_ConnectEventHandler connects,
                      GNUNET_CORE_DisconnectEventHandler disconnects,
+                    GNUNET_CORE_PeerStatusEventHandler status_events,
                      GNUNET_CORE_MessageCallback inbound_notify,
                      int inbound_hdr_only,
                      GNUNET_CORE_MessageCallback outbound_notify,
@@ -717,6 +764,7 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
   h->init = init;
   h->connects = connects;
   h->disconnects = disconnects;
+  h->status_events = status_events;
   h->inbound_notify = inbound_notify;
   h->outbound_notify = outbound_notify;
   h->inbound_hdr_only = inbound_hdr_only;
@@ -766,6 +814,7 @@ GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
     GNUNET_SCHEDULER_cancel (handle->sched, handle->reconnect_task);
   if (handle->client_notifications != NULL)
     GNUNET_CLIENT_disconnect (handle->client_notifications, GNUNET_NO);
+  GNUNET_break (handle->pending_head == NULL);
   GNUNET_free_non_null (handle->solicit_buffer);
   GNUNET_free (handle);
 }
@@ -798,11 +847,6 @@ produce_send (void *cls, size_t size, void *buf)
       trigger_next_request (h);
       return 0;
     }
-#if DEBUG_CORE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Preparing for P2P transmission to `%4s'.\n",
-             GNUNET_i2s(&th->peer));
-#endif
   sm = (struct SendMessage *) buf;
   sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND);
   sm->priority = htonl (th->priority);
@@ -812,6 +856,8 @@ produce_send (void *cls, size_t size, void *buf)
   notify_cls = th->notify_cls;
   GNUNET_CORE_notify_transmit_ready_cancel (th);
   trigger_next_request (h);
+  size = GNUNET_MIN (size,
+                    GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE);
   GNUNET_assert (size >= sizeof (struct SendMessage));
   dt = notify (notify_cls, size - sizeof (struct SendMessage), &sm[1]);
   if (0 == dt)
@@ -824,12 +870,23 @@ produce_send (void *cls, size_t size, void *buf)
       /* client decided to send nothing! */
       return 0;
     }
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Produced SEND message to core with %u bytes payload\n",
+             dt);
+#endif
   GNUNET_assert (dt >= sizeof (struct GNUNET_MessageHeader));
   if (dt + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
     {
       GNUNET_break (0);
       return 0;
     }
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Preparing for P2P transmission of %u bytes to `%4s'.\n",
+             dt,
+             GNUNET_i2s(&th->peer));
+#endif
   sm->header.size = htons (dt + sizeof (struct SendMessage));
   GNUNET_assert (dt + sizeof (struct SendMessage) <= size);
   return dt + sizeof (struct SendMessage);