i am a dumb dummy
[oweals/gnunet.git] / src / core / core_api.c
index fb975e731777fd37ed781c1f6323630ac3c87f24..21622852b441633e1d002b7ca34451d80a0e80a0 100644 (file)
@@ -23,9 +23,6 @@
  * @brief core service; this is the main API for encrypted P2P
  *        communications
  * @author Christian Grothoff
- *
- * TODO:
- * - implement atsi parsing and passing
  */
 #include "platform.h"
 #include "gnunet_constants.h"
@@ -143,6 +140,10 @@ struct ControlMessage
    */
   void *cont_cls;
 
+  /**
+   * Transmit handle (if one is associated with this ControlMessage), or NULL.
+   */
+  struct GNUNET_CORE_TransmitHandle *th;
 };
 
 
@@ -459,24 +460,35 @@ static void
 reconnect_later (struct GNUNET_CORE_Handle *h)
 {
   struct ControlMessage *cm;
+  struct PeerRecord *pr;
 
+  while (NULL != (cm = h->pending_head))
+    {
+      GNUNET_CONTAINER_DLL_remove (h->pending_head,
+                                  h->pending_tail,
+                                  cm);
+      if (cm->th != NULL)
+       cm->th->cm = NULL; 
+      if (cm->cont != NULL)
+       cm->cont (cm->cont_cls, NULL);
+      GNUNET_free (cm);
+    }
   if (h->client != NULL)
     {
       GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
       h->client = NULL;
+      h->cth = NULL;
       GNUNET_CONTAINER_multihashmap_iterate (h->peers,
                                             &disconnect_and_free_peer_entry,
                                             h);
     }
+  while (NULL != (pr = h->ready_peer_head))    
+    GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
+                                h->ready_peer_tail,
+                                pr);
+  
+  GNUNET_assert (h->pending_head == NULL);
   h->currently_down = GNUNET_YES;
-  while (NULL != (cm = h->pending_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (h->pending_head,
-                                  h->pending_tail,
-                                  cm);      
-      cm->cont (cm->cont_cls, NULL);
-      GNUNET_free (cm);
-    }
   GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
   h->retry_backoff = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
                                               h->retry_backoff);
@@ -511,22 +523,6 @@ transmission_timeout (void *cls,
                      const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
-/**
- * Control message was sent, mark it as such.
- *
- * @param cls the 'struct GNUNET_CORE_TransmitHandle*'
- * @param tc scheduler context
- */
-static void
-mark_control_message_sent (void *cls,
-                          const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct GNUNET_CORE_TransmitHandle *th = cls;
-
-  th->cm = NULL;
-}
-
-
 /**
  * Send a control message to the peer asking for transmission
  * of the message in the given peer record.
@@ -558,9 +554,8 @@ request_next_transmission (struct PeerRecord *pr)
                                                   pr);
   cm = GNUNET_malloc (sizeof (struct ControlMessage) + 
                      sizeof (struct SendMessageRequest));
-  cm->cont = &mark_control_message_sent;
-  cm->cont_cls = th;
   th->cm = cm;
+  cm->th = th;
   smr = (struct SendMessageRequest*) &cm[1];
   smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
   smr->header.size = htons (sizeof (struct SendMessageRequest));
@@ -595,14 +590,26 @@ transmission_timeout (void *cls,
                      const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct PeerRecord *pr = cls;
+  struct GNUNET_CORE_Handle *h = pr->ch;
   struct GNUNET_CORE_TransmitHandle *th;
-
+  
   pr->timeout_task = GNUNET_SCHEDULER_NO_TASK;
   th = pr->pending_head;
   GNUNET_CONTAINER_DLL_remove (pr->pending_head,
                                pr->pending_tail,
                                th);
   pr->queue_size--;
+  if ( (pr->prev != NULL) ||
+       (pr->next != NULL) ||
+       (pr == h->ready_peer_head) )
+    {
+      /* the request that was 'approved' by core was
+        canceled before it could be transmitted; remove
+        us from the 'ready' list */
+      GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
+                                  h->ready_peer_tail,
+                                  pr);
+    }
 #if DEBUG_CORE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Signalling timeout of request for transmission to CORE service\n");
@@ -659,8 +666,12 @@ transmit_message (void *cls,
       GNUNET_CONTAINER_DLL_remove (h->pending_head,
                                   h->pending_tail,
                                   cm);     
+      if (cm->th != NULL)
+       cm->th->cm = NULL;
       if (NULL != cm->cont)
-       cm->cont (cm->cont_cls, NULL);
+       GNUNET_SCHEDULER_add_continuation (cm->cont, 
+                                          cm->cont_cls,
+                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
       GNUNET_free (cm);
       trigger_next_request (h, GNUNET_NO);
       return msize;
@@ -668,6 +679,7 @@ transmit_message (void *cls,
   /* now check for 'ready' P2P messages */
   if (NULL != (pr = h->ready_peer_head))
     {
+      GNUNET_assert (pr->pending_head != NULL);
       th = pr->pending_head;
       if (size < th->msize + sizeof (struct SendMessage))
        {
@@ -767,7 +779,7 @@ trigger_next_request (struct GNUNET_CORE_Handle *h,
     }
   if (h->pending_head != NULL)
     msize = ntohs (((struct GNUNET_MessageHeader*) &h->pending_head[1])->size);    
-  else if (h->ready_peer_head != NULL)
+  else if (h->ready_peer_head != NULL) 
     msize = h->ready_peer_head->pending_head->msize + sizeof (struct SendMessage);    
   else
     {
@@ -813,6 +825,7 @@ main_notify_handler (void *cls,
   int trigger;
   uint16_t msize;
   uint16_t et;
+  uint32_t ats_count;
 
   if (msg == NULL)
     {
@@ -870,13 +883,21 @@ main_notify_handler (void *cls,
        }
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT:
-      if (msize != sizeof (struct ConnectNotifyMessage))
+      if (msize < sizeof (struct ConnectNotifyMessage))
         {
           GNUNET_break (0);
          reconnect_later (h);
          return;
         }
       cnm = (const struct ConnectNotifyMessage *) msg;
+      ats_count = ntohl (cnm->ats_count);
+      if ( (msize != sizeof (struct ConnectNotifyMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) ||
+          (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR != ntohl ((&cnm->ats)[ats_count].type)) )
+        {
+          GNUNET_break (0);
+         reconnect_later (h);
+         return;
+        }
 #if DEBUG_CORE
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Received notification about connection from `%s'.\n",
@@ -909,7 +930,7 @@ main_notify_handler (void *cls,
       if (NULL != h->connects)
        h->connects (h->cls,
                     &cnm->peer,
-                    NULL /* FIXME: atsi! */);
+                    &cnm->ats);
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT:
       if (msize != sizeof (struct DisconnectNotifyMessage))
@@ -953,7 +974,7 @@ main_notify_handler (void *cls,
           GNUNET_break (0);
           break;
         }
-      if (msize != sizeof (struct PeerStatusNotifyMessage))
+      if (msize < sizeof (struct PeerStatusNotifyMessage))
         {
           GNUNET_break (0);
          reconnect_later (h);
@@ -968,6 +989,14 @@ main_notify_handler (void *cls,
          GNUNET_break (0);
          return;
        }
+      ats_count = ntohl (psnm->ats_count);
+      if ( (msize != sizeof (struct PeerStatusNotifyMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) ||
+          (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR != ntohl ((&psnm->ats)[ats_count].type)) )
+        {
+          GNUNET_break (0);
+         reconnect_later (h);
+         return;
+        }
 #if DEBUG_CORE
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Received notification about status change by `%s'.\n",
@@ -986,12 +1015,10 @@ main_notify_handler (void *cls,
                        psnm->bandwidth_in,
                        psnm->bandwidth_out,
                        GNUNET_TIME_absolute_ntoh (psnm->timeout),
-                       NULL /* FIXME: atsi */);
+                       &psnm->ats);
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND:
-      if (msize <
-          sizeof (struct NotifyTrafficMessage) +
-          sizeof (struct GNUNET_MessageHeader))
+      if (msize < sizeof (struct NotifyTrafficMessage))
         {
           GNUNET_break (0);
          reconnect_later (h);
@@ -1006,7 +1033,16 @@ main_notify_handler (void *cls,
          GNUNET_break (0);
          return;
        }
-      em = (const struct GNUNET_MessageHeader *) &ntm[1];
+      ats_count = ntohl (ntm->ats_count);
+      if ( (msize < sizeof (struct NotifyTrafficMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)
+           + sizeof (struct GNUNET_MessageHeader)) ||
+          (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR != ntohl ((&ntm->ats)[ats_count].type)) )
+        {
+          GNUNET_break (0);
+         reconnect_later (h);
+         return;
+        }
+      em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count+1];
 #if DEBUG_CORE
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Received message of type %u and size %u from peer `%4s'\n",
@@ -1023,7 +1059,8 @@ main_notify_handler (void *cls,
          return;
        }
       if ((GNUNET_NO == h->inbound_hdr_only) &&
-          (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
+          (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + 
+          + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) )
         {
           GNUNET_break (0);
          reconnect_later (h);
@@ -1043,7 +1080,7 @@ main_notify_handler (void *cls,
             }
           if (GNUNET_OK !=
               h->handlers[hpos].callback (h->cls, &ntm->peer, em,
-                                         NULL /* FIXME: atsi */))
+                                         &ntm->ats))
             {
               /* error in processing, do not process other messages! */
               break;
@@ -1051,12 +1088,10 @@ main_notify_handler (void *cls,
         }
       if (NULL != h->inbound_notify)
         h->inbound_notify (h->cls, &ntm->peer, em,
-                          NULL /* FIXME: atsi */);
+                          &ntm->ats);
       break;
     case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND:
-      if (msize <
-          sizeof (struct NotifyTrafficMessage) +
-          sizeof (struct GNUNET_MessageHeader))
+      if (msize < sizeof (struct NotifyTrafficMessage))
         {
           GNUNET_break (0);
          reconnect_later (h);
@@ -1071,7 +1106,16 @@ main_notify_handler (void *cls,
          GNUNET_break (0);
          return;
        }
-      em = (const struct GNUNET_MessageHeader *) &ntm[1];
+      ats_count = ntohl (ntm->ats_count);
+      if ( (msize < sizeof (struct NotifyTrafficMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)
+           + sizeof (struct GNUNET_MessageHeader)) ||
+          (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR != ntohl ((&ntm->ats)[ats_count].type)) )
+        {
+          GNUNET_break (0);
+         reconnect_later (h);
+         return;
+        }
+      em = (const struct GNUNET_MessageHeader *) &(&ntm->ats)[ats_count+1];
       pr = GNUNET_CONTAINER_multihashmap_get (h->peers,
                                              &ntm->peer.hashPubKey);
       if (pr == NULL)
@@ -1086,7 +1130,8 @@ main_notify_handler (void *cls,
                  GNUNET_i2s (&ntm->peer));
 #endif
       if ((GNUNET_NO == h->outbound_hdr_only) &&
-          (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage)))
+          (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage) + 
+          + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)) )
         {
           GNUNET_break (0);
          reconnect_later (h);
@@ -1098,7 +1143,7 @@ main_notify_handler (void *cls,
           break;
         }
       h->outbound_notify (h->cls, &ntm->peer, em,
-                         NULL /* FIXME: atsi? */);
+                         &ntm->ats);
       break;
     case GNUNET_MESSAGE_TYPE_CORE_SEND_READY:
       if (msize != sizeof (struct SendMessageReady))
@@ -1129,6 +1174,13 @@ main_notify_handler (void *cls,
                  "Received notification about transmission readiness to `%s'.\n",
                  GNUNET_i2s (&smr->peer));
 #endif
+      if (pr->pending_head == NULL)
+        {
+         /* request must have been cancelled between the original request
+            and the response from core, ignore core's readiness */
+          return;
+        }
+
       th = pr->pending_head;
       if (ntohs (smr->smr_id) != th->smr_id)
        {
@@ -1370,7 +1422,7 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
 /**
  * Disconnect from the core service.  This function can only 
  * be called *after* all pending 'GNUNET_CORE_notify_transmit_ready'
- * requests have been explicitly cancelled.
+ * requests have been explicitly canceled.
  *
  * @param handle connection to core to disconnect
  */
@@ -1403,7 +1455,10 @@ GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
       GNUNET_CONTAINER_DLL_remove (handle->pending_head,
                                   handle->pending_tail,
                                   cm);
-      cm->cont (cm->cont_cls, NULL);
+      if (cm->th != NULL)
+       cm->th->cm = NULL;
+      if (cm->cont != NULL)
+       cm->cont (cm->cont_cls, NULL);
       GNUNET_free (cm);
     }
   GNUNET_CONTAINER_multihashmap_iterate (handle->peers,
@@ -1471,9 +1526,9 @@ GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
   /* bound queue size */
   if (pr->queue_size == handle->queue_size)
     {
-      /* find lowest-priority entry */
-      minp = pr->pending_head;
-      prev = minp->next;
+      /* find lowest-priority entry, but skip the head of the list */
+      minp = pr->pending_head->next;
+      prev = minp;
       while (prev != NULL)
        {
          if (prev->priority < minp->priority)
@@ -1573,7 +1628,7 @@ GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle
           (pr == h->ready_peer_head) )
        {
          /* the request that was 'approved' by core was
-            cancelled before it could be transmitted; remove
+            canceled before it could be transmitted; remove
             us from the 'ready' list */
          GNUNET_CONTAINER_DLL_remove (h->ready_peer_head,
                                       h->ready_peer_tail,
@@ -1885,71 +1940,4 @@ GNUNET_CORE_peer_change_preference_cancel (struct GNUNET_CORE_InformationRequest
 }
 
 
-#if NEW
-/* ********************* GNUNET_CORE_iterate_peers *********************** */
-
-/**
- * Context for 'iterate_peers' helper function.
- */
-struct IterationContext
-{
-  /**
-   * Callback to call.
-   */
-  GNUNET_CORE_ConnectEventHandler peer_cb;
-
-  /**
-   * Closure for 'peer_cb'.
-   */
-  void *cb_cls;
-};
-
-
-/**
- * Call callback for each peer.
- *
- * @param cls the 'struct IterationContext'
- * @param hc peer identity, not used
- * @param value the 'struct PeerRecord'
- * @return GNUNET_YES (continue iteration)
- */
-static int
-iterate_peers (void *cls,
-              const GNUNET_HashCode *hc,
-              void *value)
-{
-  struct IterationContext *ic = cls;
-  struct PeerRecord *pr = value;
-
-  ic->peer_cb (ic->cb_cls,
-              &pr->peer,
-              NULL /* FIXME: pass atsi? */);
-  return GNUNET_YES;
-}
-
-
-/**
- * Obtain statistics and/or change preferences for the given peer.
- *
- * @param h handle to core
- * @param peer_cb function to call with the peer information
- * @param cb_cls closure for peer_cb
- * @return GNUNET_OK if iterating, GNUNET_SYSERR on error
- */
-int
-GNUNET_CORE_iterate_peers (struct GNUNET_CORE_Handle *h,
-                           GNUNET_CORE_ConnectEventHandler peer_cb,
-                           void *cb_cls)
-{
-  struct IterationContext ic;
-
-  ic.peer_cb = peer_cb;
-  ic.cb_cls = cb_cls;
-  GNUNET_CONTAINER_multihashmap_iterate (h->peers,
-                                        &iterate_peers,
-                                        &ic);
-  return GNUNET_OK;
-}
-#endif
-
 /* end of core_api.c */