more bw assignment code
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
index 14e7b9a38df0524accb4c42705419cb5910d74e0..b55703caef15bf6db0544fb0c8879299128f0550 100644 (file)
@@ -26,7 +26,8 @@
  */
 #include "platform.h"
 #include "gnunet-service-ats_addresses.h"
-
+#include "gnunet-service-ats_scheduling.h"
+#include "gnunet-service-ats_reservations.h"
 
 struct ATS_Address
 {
@@ -34,20 +35,33 @@ struct ATS_Address
 
   size_t addr_len;
 
+  struct GNUNET_SERVER_Client *session_client;
+                  
   uint32_t session_id;
 
   uint32_t ats_count;
 
-  void * addr;
+  const void * addr;
 
   char * plugin;
 
   struct GNUNET_TRANSPORT_ATS_Information * ats;
+
+  struct GNUNET_BANDWIDTH_Value32NBO bw_in;
+
+  struct GNUNET_BANDWIDTH_Value32NBO bw_out;
+
 };
 
 
 static struct GNUNET_CONTAINER_MultiHashMap * addresses;
 
+static unsigned long long total_quota_in;
+
+static unsigned long long total_quota_out;
+
+static unsigned int active_addr_count;
+
 
 struct CompareAddressContext
 {
@@ -56,6 +70,24 @@ struct CompareAddressContext
 };
 
 
+static void
+destroy_address (struct ATS_Address *addr)
+{
+  GNUNET_assert (GNUNET_YES == 
+                GNUNET_CONTAINER_multihashmap_remove(addresses, 
+                                                     &addr->peer.hashPubKey, 
+                                                     addr));
+  if (ntohl (addr->bw_in.value__) > 0)
+  {
+    active_addr_count--;
+    // FIXME: update address assignment for other peers...
+  }
+  GNUNET_free_non_null (addr->ats);
+  GNUNET_free (addr->plugin);
+  GNUNET_free (addr);
+}
+
+
 static int 
 compare_address_it (void *cls,
                    const GNUNET_HashCode * key,
@@ -63,17 +95,48 @@ compare_address_it (void *cls,
 {
   struct CompareAddressContext * cac = cls;
   struct ATS_Address * aa = (struct ATS_Address *) value;
+
+  /* compare sessions */
+  if ((aa->session_client != cac->search->session_client) ||
+      (aa->session_id != cac->search->session_id))
+    return GNUNET_YES;
+
+  if (aa->addr_len != cac->search->addr_len)
+  {
+    return GNUNET_YES;
+  }
+
   if (0 == strcmp(aa->plugin, cac->search->plugin))
   {
-    if ((aa->addr_len == cac->search->addr_len) &&
-        (0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)))
-      cac->result = aa;
+    return GNUNET_YES;
+  }
+
+  if (0 == memcmp (aa->addr, cac->search->addr, aa->addr_len))
+  {
+    cac->result = aa;
     return GNUNET_NO;
   }
   return GNUNET_YES;
 }
 
 
+struct ATS_Address *
+find_address (const struct GNUNET_PeerIdentity *peer,
+              struct ATS_Address * addr)
+{
+  struct CompareAddressContext cac;
+  cac.result = NULL;
+  cac.search = addr;
+
+  GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
+         &peer->hashPubKey,
+         compare_address_it,
+         &cac);
+
+  return cac.result;
+}
+
+
 void
 GAS_address_update (const struct GNUNET_PeerIdentity *peer,
                    const char *plugin_name,
@@ -84,25 +147,65 @@ GAS_address_update (const struct GNUNET_PeerIdentity *peer,
                    uint32_t atsi_count)
 {
   struct ATS_Address * aa;
+  struct ATS_Address * old;
 
-  /* FIXME: should test first if address already exists! */
-  aa = GNUNET_malloc (sizeof (struct ATS_Address) +
-                     atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) +
-                     plugin_addr_len);
+  aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
+  aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
   aa->peer = *peer;
   aa->addr_len = plugin_addr_len;
   aa->ats_count = atsi_count;
-  aa->ats = (struct GNUNET_TRANSPORT_ATS_Information *) &aa[1];  
-  memcpy (&aa->ats, atsi, atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
-  memcpy (aa->addr, plugin_addr, plugin_addr_len);
+  memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
+  aa->addr = &aa[1];
+  memcpy (&aa[1], plugin_addr, plugin_addr_len);
   aa->plugin = GNUNET_strdup (plugin_name);
+  aa->session_client = session_client;
   aa->session_id = session_id;
+  old = find_address (peer, aa);
+  if (old == NULL)
+  {
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CONTAINER_multihashmap_put (addresses,
+                                                     &peer->hashPubKey,
+                                                     aa,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Added new address for peer `%s' %X\n",
+               GNUNET_i2s (peer), aa);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Updated existing address for peer `%s' %X \n",
+             GNUNET_i2s (peer), old);
+  GNUNET_free_non_null (old->ats);
+  old->ats = NULL;
+  old->ats_count = 0;
+  old->ats = aa->ats;
+  old->ats_count = aa->ats_count;
+  GNUNET_free (aa->plugin);
+  GNUNET_free (aa);
+}
+
+
+static int
+remove_address_by_client (void *cls,
+                         const GNUNET_HashCode * key,
+                         void *value)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct ATS_Address * aa = value;
 
-  GNUNET_assert (GNUNET_OK == 
-                GNUNET_CONTAINER_multihashmap_put(addresses, 
-                                                  &peer->hashPubKey, 
-                                                  aa, 
-                                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+  if (aa->session_client == client)
+    destroy_address (aa);  
+  return GNUNET_OK;
+}
+
+
+void
+GAS_address_client_disconnected (struct GNUNET_SERVER_Client *client)
+{
+  if (addresses != NULL)
+    GNUNET_CONTAINER_multihashmap_iterate(addresses, 
+                                         &remove_address_by_client, client);
 }
 
 
@@ -113,30 +216,82 @@ GAS_address_destroyed (const struct GNUNET_PeerIdentity *peer,
                       struct GNUNET_SERVER_Client *session_client,
                       uint32_t session_id)
 {
-#if 0
-  struct ATS_Address * aa;
 
-  aa = find_address (peer, plugin_name, plugin_addr, plugin_addr_len, 
-                    session_client, session_id);
-  GNUNET_break (GNUNET_YES ==
-               GNUNET_CONTAINER_multihashmap_remove(addresses, &peer->hashPubKey, aa));
-  GNUNET_free (aa);
-#endif
+  struct ATS_Address aa;
+  struct ATS_Address *res;
+
+  aa.peer = *peer;
+  aa.addr_len = plugin_addr_len;
+  aa.addr = plugin_addr;
+  aa.plugin = (char*) plugin_name;
+  aa.session_client = session_client;
+  aa.session_id = session_id;
+
+  res = find_address (peer, &aa);
+  if (res == NULL)
+  {
+    /* we don't even know this one, can this happen? */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Asked to delete unknown address for peer `%s'\n",
+               GNUNET_i2s (peer));
+    return; 
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Deleting address for peer `%s': `%s'\n",
+             GNUNET_i2s (peer), plugin_name);
+  destroy_address (res);
 }
 
 
 void
 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
 {
+  struct ATS_Address * aa;
+
+  aa = GNUNET_CONTAINER_multihashmap_get (addresses, &peer->hashPubKey);
+  if (aa == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Cannot suggest address for peer `%s'\n",
+               GNUNET_i2s (peer));
+    return; 
+  }
+  /* FIXME: ensure that we don't do this multiple times per peer! */
+  if (ntohl (aa->bw_in.value__) == 0)
+  {
+    active_addr_count++;
+    aa->bw_in.value__ = htonl (total_quota_in / active_addr_count);
+    aa->bw_out.value__ = htonl (total_quota_out / active_addr_count);
+    /* FIXME: update bw assignments for other addresses... */
+  }
+  GAS_reservations_set_bandwidth (peer,
+                                 aa->bw_in);
+  GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, 
+                                             aa->addr, aa->addr_len, 
+                                             aa->session_client, aa->session_id, 
+                                             aa->ats, aa->ats_count, 
+                                             aa->bw_out, aa->bw_in);
 }
 
 
 /**
  * Initialize address subsystem.
+ *
+ * @param cfg configuration to use
  */
 void
-GAS_addresses_init ()
+GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_number (cfg,
+                                                       "core",
+                                                       "TOTAL_QUOTA_IN",
+                                                       &total_quota_in));
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_number (cfg,
+                                                       "core",
+                                                       "TOTAL_QUOTA_OUT",
+                                                       &total_quota_out));
   addresses = GNUNET_CONTAINER_multihashmap_create(128);
 }
 
@@ -154,8 +309,12 @@ free_address_it (void *cls,
                 const GNUNET_HashCode * key,
                 void *value)
 {
-  struct ATS_Address * aa = cls;
-  GNUNET_free (aa);
+  struct ATS_Address * aa = value;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+    "Freeing address for peer `%s' %X\n",
+    GNUNET_i2s (&aa->peer), aa);
+  GNUNET_CONTAINER_multihashmap_remove (addresses, key, value);
+  destroy_address (aa);
   return GNUNET_OK;
 }
 
@@ -169,6 +328,7 @@ GAS_addresses_done ()
 {
   GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL);
   GNUNET_CONTAINER_multihashmap_destroy (addresses);
+  addresses = NULL;
 }