Allowed to destroy NULL paths
[oweals/gnunet.git] / src / mesh / mesh_api.c
index 3a50e44ee83790e18d7edaebcd31c4ed374da9f4..30bd13f46d421104256c4201cbf01fe09df54e80 100644 (file)
 #include <gnunet_constants.h>
 #include <gnunet_mesh_service.h>
 #include <gnunet_core_service.h>
+#include <gnunet_transport_service.h>
 #include <gnunet_container_lib.h>
 #include <gnunet_applications.h>
 
+#define LOG(kind,...) GNUNET_log_from (kind, "mesh-api",__VA_ARGS__)
+
 struct tunnel_id
 {
   uint32_t id GNUNET_PACKED;
@@ -110,8 +113,14 @@ struct peer_list_element
   /* list of application-types */
   struct type_list_element *type_head, *type_tail;
 
-  struct GNUNET_TRANSPORT_ATS_Information atsi;
   struct peer_list_element *next, *prev;
+
+  /* The handle that sends the hellos to this peer */
+  struct GNUNET_CORE_TransmitHandle *hello;
+
+  GNUNET_SCHEDULER_TaskIdentifier sched;
+
+  struct GNUNET_MESH_Handle *handle;
 };
 
 struct peer_list
@@ -122,6 +131,7 @@ struct peer_list
 struct GNUNET_MESH_Handle
 {
   struct GNUNET_CORE_Handle *core;
+  struct GNUNET_TRANSPORT_Handle *transport;
   struct GNUNET_MESH_MessageHandler *handlers;
   struct GNUNET_PeerIdentity myself;
   unsigned int connected_to_core;
@@ -143,7 +153,7 @@ send_end_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   struct GNUNET_MESH_Tunnel *tunnel = cls;
 
-  tunnel->connect_handler (tunnel->handler_cls, NULL, NULL);
+  tunnel->connect_handler (tunnel->handler_cls, NULL, NULL, 0);
 }
 
 static void
@@ -154,7 +164,7 @@ send_self_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   struct GNUNET_MESH_Tunnel *tunnel = cls;
 
-  tunnel->connect_handler (tunnel->handler_cls, &tunnel->handle->myself, NULL);
+  tunnel->connect_handler (tunnel->handler_cls, &tunnel->handle->myself, NULL, 0);
   GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
 }
 
@@ -166,16 +176,14 @@ call_connect_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   struct GNUNET_MESH_Tunnel *tunnel = cls;
 
-  tunnel->connect_handler (tunnel->handler_cls, &tunnel->peer, NULL);
+  tunnel->connect_handler (tunnel->handler_cls, &tunnel->peer, NULL, 0);
   GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
 }
 
 static void
 core_startup (void *cls, struct GNUNET_CORE_Handle *core
               __attribute__ ((unused)),
-              const struct GNUNET_PeerIdentity *my_identity,
-              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey
-              __attribute__ ((unused)))
+              const struct GNUNET_PeerIdentity *my_identity)
 {
   struct GNUNET_MESH_Handle *handle = cls;
 
@@ -189,9 +197,12 @@ send_hello_message (void *cls, size_t size, void *buf)
   if (cls == NULL)
     return 0;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending hello\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending hello\n");
 
-  struct GNUNET_MESH_Handle *handle = cls;
+  struct peer_list_element *element = cls;
+  struct GNUNET_MESH_Handle *handle = element->handle;
+
+  element->hello = NULL;
   struct GNUNET_MessageHeader *hdr = buf;
 
   size_t sent =
@@ -207,6 +218,32 @@ send_hello_message (void *cls, size_t size, void *buf)
   return sent;
 }
 
+void
+schedule_hello_message (void *cls,
+                        const struct GNUNET_SCHEDULER_TaskContext *tctx)
+{
+  struct peer_list_element *element = cls;
+
+  element->sched = GNUNET_SCHEDULER_NO_TASK;
+
+  if ((tctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+    return;
+
+  if (element->hello == NULL)
+    element->hello =
+        GNUNET_CORE_notify_transmit_ready (element->handle->core, GNUNET_NO, 42,
+                                           GNUNET_TIME_UNIT_SECONDS,
+                                           &element->peer,
+                                           sizeof (struct GNUNET_MessageHeader)
+                                           +
+                                           element->handle->hello_message_size,
+                                           &send_hello_message, element);
+
+  element->sched =
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                    schedule_hello_message, cls);
+}
+
 
 /**
  * Core calls this if we are connected to a new peer.
@@ -216,29 +253,22 @@ send_hello_message (void *cls, size_t size, void *buf)
  */
 static void
 core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
-              const struct GNUNET_TRANSPORT_ATS_Information *atsi)
+              const struct GNUNET_ATS_Information *atsi,
+             unsigned int atsi_count)
 {
   struct GNUNET_MESH_Handle *handle = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Core tells us we are connected to peer %s\n", GNUNET_i2s (peer));
-
-  /* Send a hello to this peer */
-  GNUNET_CORE_notify_transmit_ready (handle->core, GNUNET_NO, 42,
-                                     GNUNET_TIME_UNIT_SECONDS, peer,
-                                     sizeof (struct GNUNET_MessageHeader) +
-                                     handle->hello_message_size,
-                                     &send_hello_message, cls);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Core tells us we are connected to peer %s\n",
+       GNUNET_i2s (peer));
 
   /* put the new peer into the list of connected peers */
   struct peer_list_element *element =
       GNUNET_malloc (sizeof (struct peer_list_element));
   memcpy (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity));
+  element->handle = handle;
 
-  if (NULL != atsi)
-    memcpy (&element->atsi, atsi,
-            sizeof (struct GNUNET_TRANSPORT_ATS_Information));
-
+  /* Send a hello to this peer */
+  element->sched = GNUNET_SCHEDULER_add_now (schedule_hello_message, element);
   GNUNET_CONTAINER_DLL_insert_after (handle->connected_peers.head,
                                      handle->connected_peers.tail,
                                      handle->connected_peers.tail, element);
@@ -259,7 +289,7 @@ core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
                                          handle->established_tunnels.tail,
                                          handle->established_tunnels.tail,
                                          tunnel);
-      tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls, peer, atsi);
+      tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls, peer, atsi, atsi_count);
       GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
       tunnel = next;
     }
@@ -279,9 +309,9 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
 {
   struct GNUNET_MESH_Handle *handle = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Core tells us we are no longer connected to peer %s\n",
-              GNUNET_i2s (peer));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Core tells us we are no longer connected to peer %s\n",
+       GNUNET_i2s (peer));
 
   struct peer_list_element *element = handle->connected_peers.head;
 
@@ -303,6 +333,9 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
                                    tail);
       GNUNET_free (tail);
     }
+    if (element->hello != NULL)
+      GNUNET_CORE_notify_transmit_ready_cancel (element->hello);
+    GNUNET_SCHEDULER_cancel (element->sched);
     GNUNET_free (element);
   }
 
@@ -345,7 +378,8 @@ core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
 static int
 receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
                const struct GNUNET_MessageHeader *message,
-               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
+               const struct GNUNET_ATS_Information *atsi,
+              unsigned int atsi_count)
 {
   struct GNUNET_MESH_Handle *handle = cls;
   uint16_t *num = (uint16_t *) (message + 1);
@@ -353,9 +387,9 @@ receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
       (GNUNET_MESH_ApplicationType *) (num + 1);
   unsigned int i;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "The peer %s tells us he supports %d application-types.\n",
-              GNUNET_i2s (other), ntohs (*num));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "The peer %s tells us he supports %d application-types.\n",
+       GNUNET_i2s (other), ntohs (*num));
 
   struct peer_list_element *element = handle->connected_peers.head;
 
@@ -371,9 +405,9 @@ receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
 
   for (i = 0; i < ntohs (*num); i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "The peer %s newly supports the application-type %d\n",
-                GNUNET_i2s (other), ntohs (ports[i]));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "The peer %s newly supports the application-type %d\n",
+         GNUNET_i2s (other), ntohs (ports[i]));
     if (GNUNET_APPLICATION_TYPE_END == ntohs (ports[i]))
       continue;
     struct type_list_element *new_type = GNUNET_malloc (sizeof *new_type);
@@ -387,9 +421,9 @@ receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
 
   for (type = element->type_head; type != NULL; type = type->next)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "The peer %s supports the application-type %d\n",
-                GNUNET_i2s (other), type->type);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "The peer %s supports the application-type %d\n", GNUNET_i2s (other),
+         type->type);
   }
 
   struct tunnel_list_element *tunnel = handle->pending_by_type_tunnels.head;
@@ -412,7 +446,7 @@ receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
         memcpy (&tunnel->tunnel.peer, other,
                 sizeof (struct GNUNET_PeerIdentity));
         tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
-                                        &tunnel->tunnel.peer, atsi);
+                                        &tunnel->tunnel.peer, atsi, atsi_count);
         GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
         break;
       }
@@ -431,7 +465,8 @@ receive_hello (void *cls, const struct GNUNET_PeerIdentity *other,
 static int
 core_receive (void *cls, const struct GNUNET_PeerIdentity *other,
               const struct GNUNET_MessageHeader *message,
-              const struct GNUNET_TRANSPORT_ATS_Information *atsi)
+              const struct GNUNET_ATS_Information *atsi,
+             unsigned int atsi_count)
 {
   struct GNUNET_MESH_Handle *handle = cls;
   struct tunnel_message *tmessage = (struct tunnel_message *) message;
@@ -455,9 +490,9 @@ core_receive (void *cls, const struct GNUNET_PeerIdentity *other,
   /* If no handler was found, drop the message but keep the channel open */
   if (handler->callback == NULL)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Received message of type %d from peer %s; dropping it.\n",
-                ntohs (rmessage->type), GNUNET_i2s (other));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received message of type %d from peer %s; dropping it.\n",
+         ntohs (rmessage->type), GNUNET_i2s (other));
     return GNUNET_OK;
   }
 
@@ -479,9 +514,9 @@ core_receive (void *cls, const struct GNUNET_PeerIdentity *other,
   /* if no tunnel was found: create a new inbound tunnel */
   if (tunnel == NULL)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "New inbound tunnel from peer %s; first message has type %d.\n",
-                GNUNET_i2s (other), ntohs (rmessage->type));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "New inbound tunnel from peer %s; first message has type %d.\n",
+         GNUNET_i2s (other), ntohs (rmessage->type));
     tunnel = GNUNET_malloc (sizeof (struct tunnel_list_element));
     tunnel->tunnel.connect_handler = NULL;
     tunnel->tunnel.disconnect_handler = NULL;
@@ -497,12 +532,11 @@ core_receive (void *cls, const struct GNUNET_PeerIdentity *other,
                                        tunnel);
   }
   else
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Inbound message from peer %s; type %d.\n", GNUNET_i2s (other),
-                ntohs (rmessage->type));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Inbound message from peer %s; type %d.\n",
+         GNUNET_i2s (other), ntohs (rmessage->type));
 
   return handler->callback (handle->cls, &tunnel->tunnel, &tunnel->tunnel.ctx,
-                            other, rmessage, atsi);
+                            other, rmessage, atsi, atsi_count);
 }
 
 struct GNUNET_MESH_Tunnel *
@@ -532,8 +566,8 @@ GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Handle *handle,
     element = element->next;
   }
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect by tupe %d.\n",
-              application_type);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect by tupe %d.\n",
+       application_type);
 
   /* Put into pending list */
   struct tunnel_list_element *tunnel =
@@ -621,7 +655,7 @@ GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle,
     GNUNET_CONTAINER_DLL_insert_after (handle->pending_tunnels.head,
                                        handle->pending_tunnels.tail,
                                        handle->pending_tunnels.tail, tunnel);
-    (void) GNUNET_CORE_peer_request_connect (handle->core, peers, NULL, NULL);
+    GNUNET_TRANSPORT_try_connect (handle->transport, peers);
   }
 
   return &tunnel->tunnel;
@@ -638,8 +672,11 @@ core_notify (void *cls, size_t size, void *buf)
 {
   struct notify_cls *ncls = cls;
   struct GNUNET_MESH_Tunnel *tunnel = ncls->tunnel;
-
   tunnel->notify_handle = NULL;
+
+  if (NULL == buf)
+    return ncls->notify (ncls->notify_cls, 0, NULL);
+
   struct tunnel_message *message = buf;
   void *cbuf = (void *) &message[1];
 
@@ -673,7 +710,7 @@ core_notify (void *cls, size_t size, void *buf)
  * @param cork is corking allowed for this transmission?
  * @param priority how important is the message?
  * @param maxdelay how long can the message wait?
- * @param target destination for the message, NULL for multicast to all tunnel targets 
+ * @param target destination for the message, NULL for multicast to all tunnel targets
  * @param notify_size how many bytes of buffer space does notify want?
  * @param notify function to call when buffer space is available;
  *        will be called with NULL on timeout or if the overall queue
@@ -770,7 +807,7 @@ build_hello_message (struct GNUNET_MESH_Handle *handle,
 
   for (t = stypes; *t != GNUNET_APPLICATION_TYPE_END; t++, num++) ;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I can handle %d app-types.\n", num);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "I can handle %d app-types.\n", num);
 
   handle->hello_message_size = sizeof (uint16_t) +      /* For the number of types */
       num * sizeof (GNUNET_MESH_ApplicationType);       /* For the types */
@@ -785,8 +822,7 @@ build_hello_message (struct GNUNET_MESH_Handle *handle,
 
   for (i = 0; i < num; i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I can handle the app-type %d\n",
-                stypes[i]);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "I can handle the app-type %d\n", stypes[i]);
     types[i] = htons (stypes[i]);
   }
 
@@ -833,8 +869,9 @@ GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
 
   ret->core =
       GNUNET_CORE_connect (cfg, 42, ret, &core_startup, &core_connect,
-                           &core_disconnect, NULL, NULL, GNUNET_NO, NULL,
-                           GNUNET_NO, core_handlers);
+                           &core_disconnect, NULL, GNUNET_NO, NULL, GNUNET_NO,
+                           core_handlers);
+  ret->transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL);
   return ret;
 }
 
@@ -844,6 +881,7 @@ GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
   GNUNET_free (handle->handlers);
   GNUNET_free (handle->hello_message);
   GNUNET_CORE_disconnect (handle->core);
+  GNUNET_TRANSPORT_disconnect (handle->transport);
 
   struct peer_list_element *element = handle->connected_peers.head;
 
@@ -859,6 +897,8 @@ GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
                                    tail);
       GNUNET_free (tail);
     }
+    GNUNET_CORE_notify_transmit_ready_cancel (element->hello);
+    GNUNET_SCHEDULER_cancel (element->sched);
     GNUNET_free (element);
     element = next;
   }