fix
[oweals/gnunet.git] / src / core / core_api.c
index 21ce09aec1660da6bca7a4d15569c46d006e5975..4672c7843ee6b4157c91069ba6794359659c16e6 100644 (file)
@@ -55,15 +55,21 @@ struct GNUNET_CORE_Handle
    */
   GNUNET_CORE_StartupCallback init;
 
+  /**
+   * Function to call whenever we're notified about a peer connecting
+   * (pre-connects, no session key exchange yet).
+   */
+  GNUNET_CORE_ConnectEventHandler pre_connects;
+
   /**
    * Function to call whenever we're notified about a peer connecting.
    */
-  GNUNET_CORE_ClientEventHandler connects;
+  GNUNET_CORE_ConnectEventHandler connects;
 
   /**
    * Function to call whenever we're notified about a peer disconnecting.
    */
-  GNUNET_CORE_ClientEventHandler disconnects;
+  GNUNET_CORE_DisconnectEventHandler disconnects;
 
   /**
    * Function to call whenever we receive an inbound message.
@@ -81,9 +87,9 @@ struct GNUNET_CORE_Handle
   const struct GNUNET_CORE_MessageHandler *handlers;
 
   /**
-   * Our connection to the service.
+   * Our connection to the service for notifications.
    */
-  struct GNUNET_CLIENT_Connection *client;
+  struct GNUNET_CLIENT_Connection *client_notifications;
 
   /**
    * Handle for our current transmission request.
@@ -185,17 +191,6 @@ struct GNUNET_CORE_TransmitHandle
    */
   void *get_message_cls;
 
-  /**
-   * If this entry is for a configuration request, pointer
-   * to the information callback; otherwise NULL.
-   */
-  GNUNET_CORE_PeerConfigurationInfoCallback info;
-
-  /**
-   * Closure for info.
-   */
-  void *info_cls;
-
   /**
    * If this entry is for a transmission request, pointer
    * to the notify callback; otherwise NULL.
@@ -236,6 +231,10 @@ struct GNUNET_CORE_TransmitHandle
 };
 
 
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
 /**
  * Function called when we are ready to transmit our
  * "START" message (or when this operation timed out).
@@ -257,15 +256,22 @@ static size_t transmit_start (void *cls, size_t size, void *buf);
 static void
 reconnect (struct GNUNET_CORE_Handle *h)
 {
-  GNUNET_CLIENT_disconnect (h->client);
+  if (h->client_notifications != NULL)
+    GNUNET_CLIENT_disconnect (h->client_notifications, GNUNET_NO);
   h->currently_down = GNUNET_YES;
-  h->client = GNUNET_CLIENT_connect (h->sched, "core", h->cfg);
-  h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
-                                               sizeof (struct InitMessage) +
-                                               sizeof (uint16_t) * h->hcnt,
-                                               GNUNET_TIME_UNIT_SECONDS,
-                                              GNUNET_NO,
-                                               &transmit_start, h);
+  h->client_notifications = GNUNET_CLIENT_connect (h->sched, "core", h->cfg);
+  if (h->client_notifications == NULL)
+    h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->sched,
+                                                     GNUNET_TIME_UNIT_SECONDS,
+                                                     &reconnect_task,
+                                                     h);
+  else
+    h->th = GNUNET_CLIENT_notify_transmit_ready (h->client_notifications,
+                                                sizeof (struct InitMessage) +
+                                                sizeof (uint16_t) * h->hcnt,
+                                                GNUNET_TIME_UNIT_SECONDS,
+                                                GNUNET_NO,
+                                                &transmit_start, h);
 }
 
 
@@ -281,11 +287,8 @@ timeout_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_CORE_TransmitHandle *th = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Transmission request timed out.\n");
   th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL));
-  GNUNET_CORE_notify_transmit_ready_cancel (th);
 }
 
 
@@ -341,14 +344,24 @@ static void
 trigger_next_request (struct GNUNET_CORE_Handle *h)
 {
   struct GNUNET_CORE_TransmitHandle *th;
+
   if (h->currently_down)
-    return;                     /* connection temporarily down */
+    {
+#if DEBUG_CORE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "In trigger_next_request, connection currently down...\n");
+#endif
+      return;                     /* connection temporarily down */
+    }
   if (NULL == (th = h->pending_head))
     return;                     /* no requests pending */
   GNUNET_assert (NULL == h->th);
-  GNUNET_SCHEDULER_cancel (h->sched, th->timeout_task);
-  th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
+  if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task)
+    {
+      GNUNET_SCHEDULER_cancel (h->sched, th->timeout_task);
+      th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+  h->th = GNUNET_CLIENT_notify_transmit_ready (h->client_notifications,
                                                th->msize,
                                                GNUNET_TIME_absolute_get_remaining
                                                (th->timeout), 
@@ -359,19 +372,19 @@ trigger_next_request (struct GNUNET_CORE_Handle *h)
 
 
 /**
- * Handler for most messages received from the core.
+ * Handler for notification messages received from the core.
  *
  * @param cls our "struct GNUNET_CORE_Handle"
  * @param msg the message received from the core service
  */
 static void
-main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 {
   struct GNUNET_CORE_Handle *h = cls;
   unsigned int hpos;
   const struct ConnectNotifyMessage *cnm;
+  const struct DisconnectNotifyMessage *dnm;
   const struct NotifyTrafficMessage *ntm;
-  const struct ConfigurationInfoMessage *cim;
   const struct GNUNET_MessageHeader *em;
   uint16_t msize;
   uint16_t et;
@@ -393,6 +406,23 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
 #endif
   switch (ntohs (msg->type))
     {
+    case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PRE_CONNECT:
+      if (NULL == h->pre_connects)
+        {
+          GNUNET_break (0);
+          break;
+        }
+      if (msize != sizeof (struct ConnectNotifyMessage))
+        {
+          GNUNET_break (0);
+          break;
+        }
+      cnm = (const struct ConnectNotifyMessage *) msg;
+      h->pre_connects (h->cls,
+                      &cnm->peer,
+                      GNUNET_TIME_relative_ntoh (cnm->latency),
+                      ntohl (cnm->distance));
+      break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT:
       if (NULL == h->connects)
         {
@@ -406,7 +436,9 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
         }
       cnm = (const struct ConnectNotifyMessage *) msg;
       h->connects (h->cls,
-                  &cnm->peer);
+                  &cnm->peer,
+                  GNUNET_TIME_relative_ntoh (cnm->latency),
+                  ntohl (cnm->distance));
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT:
       if (NULL == h->disconnects)
@@ -414,14 +446,14 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
           GNUNET_break (0);
           break;
         }
-      if (msize != sizeof (struct ConnectNotifyMessage))
+      if (msize != sizeof (struct DisconnectNotifyMessage))
         {
           GNUNET_break (0);
           break;
         }
-      cnm = (const struct ConnectNotifyMessage *) msg;
+      dnm = (const struct DisconnectNotifyMessage *) msg;
       h->disconnects (h->cls,
-                     &cnm->peer);
+                     &dnm->peer);
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
       if (msize <
@@ -457,7 +489,9 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
               continue;
             }
           if (GNUNET_OK !=
-              h->handlers[hpos].callback (h->cls, &ntm->peer, em))
+              h->handlers[hpos].callback (h->cls, &ntm->peer, em,
+                                         GNUNET_TIME_relative_ntoh (ntm->latency),
+                                         ntohl (ntm->distance)))
             {
               /* error in processing, disconnect ! */
               reconnect (h);
@@ -465,7 +499,9 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
             }
         }
       if (NULL != h->inbound_notify)
-        h->inbound_notify (h->cls, &ntm->peer, em);
+        h->inbound_notify (h->cls, &ntm->peer, em,
+                          GNUNET_TIME_relative_ntoh (ntm->latency),
+                          ntohl (ntm->distance));
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND:
       if (msize <
@@ -488,41 +524,19 @@ main_handler (void *cls, const struct GNUNET_MessageHeader *msg)
           GNUNET_break (0);
           break;
         }
-      h->outbound_notify (h->cls, &ntm->peer, em);
-      break;
-    case GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO:
-      if (msize != sizeof (struct ConfigurationInfoMessage))
-        {
-          GNUNET_break (0);
-          break;
-        }
-      if (NULL == h->submitted)
-        break;
-      cim = (const struct ConfigurationInfoMessage *) msg;
-
-      /* process configuration data */
-      if (h->submitted->info != NULL)
-        h->submitted->info (h->submitted->info_cls,
-                            &h->submitted->peer,
-                            ntohl (cim->bpm_in),
-                            ntohl (cim->bpm_out),
-                            GNUNET_TIME_relative_ntoh (cim->latency),
-                            (int) ntohl (cim->reserved_amount),
-                            cim->preference);
-      /* done, clean up! */      
-      GNUNET_CORE_notify_transmit_ready_cancel (h->submitted); // HUH?
-      trigger_next_request (h);
+      h->outbound_notify (h->cls, &ntm->peer, em,
+                         GNUNET_TIME_relative_ntoh (ntm->latency),
+                         ntohl (ntm->distance));
       break;
     default:
       GNUNET_break (0);
       break;
     }
-  GNUNET_CLIENT_receive (h->client,
-                         &main_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
+  GNUNET_CLIENT_receive (h->client_notifications,
+                         &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
 
-
 /**
  * Function called when we are ready to transmit our
  * "START" message (or when this operation timed out).
@@ -568,21 +582,16 @@ init_reply_handler (void *cls, const struct GNUNET_MessageHeader *msg)
   /* start our message processing loop */
 #if DEBUG_CORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _
-              ("Successfully connected to core service, starting processing loop.\n"));
+             "Successfully connected to core service, starting processing loop.\n");
 #endif
   h->currently_down = GNUNET_NO;
   trigger_next_request (h);
-  GNUNET_CLIENT_receive (h->client,
-                         &main_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
+  GNUNET_CLIENT_receive (h->client_notifications,
+                         &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
   if (NULL != (init = h->init))
     {
       /* mark so we don't call init on reconnect */
       h->init = NULL;
-#if DEBUG_CORE
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Successfully connected to core service.\n"));
-#endif
       GNUNET_CRYPTO_hash (&m->publicKey,
                           sizeof (struct
                                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
@@ -653,6 +662,8 @@ transmit_start (void *cls, size_t size, void *buf)
   init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT);
   init->header.size = htons (msize);
   opt = GNUNET_CORE_OPTION_NOTHING;
+  if (h->pre_connects != NULL)
+    opt |= GNUNET_CORE_OPTION_SEND_PRE_CONNECT;
   if (h->connects != NULL)
     opt |= GNUNET_CORE_OPTION_SEND_CONNECT;
   if (h->disconnects != NULL)
@@ -675,7 +686,7 @@ transmit_start (void *cls, size_t size, void *buf)
   ts = (uint16_t *) & init[1];
   for (hpos = 0; hpos < h->hcnt; hpos++)
     ts[hpos] = htons (h->handlers[hpos].type);
-  GNUNET_CLIENT_receive (h->client,
+  GNUNET_CLIENT_receive (h->client_notifications,
                          &init_reply_handler,
                          h,
                          GNUNET_TIME_absolute_get_remaining
@@ -694,6 +705,7 @@ transmit_start (void *cls, size_t size, void *buf)
  * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
  * @param init callback to call on timeout or once we have successfully
  *        connected to the core service; note that timeout is only meaningful if init is not NULL
+ * @param pre_connects function to call on peer pre-connect (no session key yet), can be 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 inbound_notify function to call for all inbound messages, can be NULL
@@ -714,8 +726,9 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
                      struct GNUNET_TIME_Relative timeout,
                      void *cls,
                      GNUNET_CORE_StartupCallback init,
-                     GNUNET_CORE_ClientEventHandler connects,
-                     GNUNET_CORE_ClientEventHandler disconnects,
+                     GNUNET_CORE_ConnectEventHandler pre_connects,
+                     GNUNET_CORE_ConnectEventHandler connects,
+                     GNUNET_CORE_DisconnectEventHandler disconnects,
                      GNUNET_CORE_MessageCallback inbound_notify,
                      int inbound_hdr_only,
                      GNUNET_CORE_MessageCallback outbound_notify,
@@ -729,6 +742,7 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
   h->cfg = cfg;
   h->cls = cls;
   h->init = init;
+  h->pre_connects = pre_connects;
   h->connects = connects;
   h->disconnects = disconnects;
   h->inbound_notify = inbound_notify;
@@ -736,8 +750,8 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
   h->inbound_hdr_only = inbound_hdr_only;
   h->outbound_hdr_only = outbound_hdr_only;
   h->handlers = handlers;
-  h->client = GNUNET_CLIENT_connect (sched, "core", cfg);
-  if (h->client == NULL)
+  h->client_notifications = GNUNET_CLIENT_connect (sched, "core", cfg);
+  if (h->client_notifications == NULL)
     {
       GNUNET_free (h);
       return NULL;
@@ -755,7 +769,7 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched,
               timeout.value);
 #endif
   h->th =
-    GNUNET_CLIENT_notify_transmit_ready (h->client,
+    GNUNET_CLIENT_notify_transmit_ready (h->client_notifications,
                                          sizeof (struct InitMessage) +
                                          sizeof (uint16_t) * h->hcnt, timeout,
                                         GNUNET_YES,
@@ -778,7 +792,8 @@ GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
     GNUNET_CORE_notify_transmit_ready_cancel (handle->solicit_transmit_req);
   if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
     GNUNET_SCHEDULER_cancel (handle->sched, handle->reconnect_task);
-  GNUNET_CLIENT_disconnect (handle->client);
+  if (handle->client_notifications != NULL)
+    GNUNET_CLIENT_disconnect (handle->client_notifications, GNUNET_NO);
   GNUNET_free_non_null (handle->solicit_buffer);
   GNUNET_free (handle);
 }
@@ -807,8 +822,7 @@ produce_send (void *cls, size_t size, void *buf)
                  GNUNET_i2s(&th->peer));
 #endif
       GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL));
-      if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
-        GNUNET_CORE_notify_transmit_ready_cancel (th);
+      GNUNET_CORE_notify_transmit_ready_cancel (th);
       trigger_next_request (h);
       return 0;
     }
@@ -831,12 +845,22 @@ produce_send (void *cls, size_t size, void *buf)
   dt = notify (notify_cls, size - sizeof (struct SendMessage), &sm[1]);
   if (0 == dt)
     {
+#if DEBUG_CORE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Size of clients message to peer %s is 0!\n",
+              GNUNET_i2s(&th->peer));
+#endif
       /* client decided to send nothing! */
       return 0;
     }
   GNUNET_assert (dt >= sizeof (struct GNUNET_MessageHeader));
+  if (dt + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+    {
+      GNUNET_break (0);
+      return 0;
+    }
   sm->header.size = htons (dt + sizeof (struct SendMessage));
-  GNUNET_assert (dt + sizeof (struct SendMessage) < size);
+  GNUNET_assert (dt + sizeof (struct SendMessage) <= size);
   return dt + sizeof (struct SendMessage);
 }