- fix
[oweals/gnunet.git] / src / transport / gnunet-service-transport_manipulation.c
index c00d2b64e8505bf33c163616ad3a1a56bed09ee0..c034569032a960be1d04b94089a0546561123872 100644 (file)
@@ -22,7 +22,7 @@
  * @file transport/gnunet-service-transport_manipulation.c
  * @brief transport component manipulation traffic for simulation
  * @author Christian Grothoff
- * @author
+ * @author Matthias Wachs
  */
 #include "platform.h"
 #include "gnunet-service-transport_blacklist.h"
 #include "gnunet-service-transport.h"
 #include "transport.h"
 
-static struct GNUNET_CONTAINER_MultiHashMap *peers;
-
 #define DELAY 0
 #define DISTANCE 1
 
+
+enum TRAFFIC_METRIC_DIRECTION
+{
+       TM_SEND = 0,
+       TM_RECEIVE = 1,
+       TM_BOTH = 2
+};
+
+struct GST_ManipulationHandle man_handle;
+
+
+struct GST_ManipulationHandle
+{
+       struct GNUNET_CONTAINER_MultiHashMap *peers;
+
+       /**
+        * General inbound delay
+        */
+       struct GNUNET_TIME_Relative delay_recv;
+
+       /**
+        * General outbound delay
+        */
+       struct GNUNET_TIME_Relative delay_send;
+
+       /**
+        * General inbound distance
+        */
+        unsigned long long  distance_recv;
+
+       /**
+        * General outbound distance
+        */
+        unsigned long long distance_send;
+
+};
+
+
 struct TM_Peer;
 
+
+
 struct DelayQueueEntry
 {
        struct DelayQueueEntry *prev;
@@ -133,20 +171,68 @@ GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
     const struct GNUNET_MessageHeader *message)
 {
        struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
+       struct GNUNET_PeerIdentity dummy;
        struct GNUNET_ATS_Information *ats;
        struct TM_Peer *tmp;
        uint32_t type;
        uint32_t value;
+       uint16_t direction;
        int c;
        int c2;
 
        if (0 == ntohs (tm->ats_count))
          GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
 
+       switch (ntohs(tm->direction)) {
+               case 1:
+                       direction = TM_SEND;
+                       break;
+               case 2:
+                       direction = TM_RECEIVE;
+                       break;
+               case 3:
+                       direction = TM_BOTH;
+                       break;
+               default:
+                       break;
+       }
+
+       memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
+       if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
+       {
+                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
+
+                       ats = (struct GNUNET_ATS_Information *) &tm[1];
+                       for (c = 0; c < ntohs (tm->ats_count); c++)
+                       {
+                                       type = htonl (ats[c].type);
+                                       value = htonl (ats[c].value);
+
+                                       switch (type) {
+                                               case GNUNET_ATS_QUALITY_NET_DELAY:
+                                                       if ((TM_RECEIVE == direction) || (TM_BOTH == direction))
+                                                                       man_handle.delay_recv.rel_value = value;
+                                                       if ((TM_SEND == direction) || (TM_BOTH == direction))
+                                                                       man_handle.delay_send.rel_value = value;
+                                                       break;
+                                               case GNUNET_ATS_QUALITY_NET_DISTANCE:
+                                                       if ((TM_RECEIVE == direction) || (TM_BOTH == direction))
+                                                                       man_handle.distance_recv = value;
+                                                       if ((TM_SEND == direction) || (TM_BOTH == direction))
+                                                                       man_handle.distance_send = value;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+
+                       }
+                       return;
+       }
+
        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
                        GNUNET_i2s(&tm->peer));
 
-       if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &tm->peer.hashPubKey)))
+       if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
        {
                        tmp = GNUNET_malloc (sizeof (struct TM_Peer));
                        tmp->peer = (tm->peer);
@@ -157,7 +243,7 @@ GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
                                                        tmp->metrics[c][c2] = UINT32_MAX;
                                        }
                        }
-                       GNUNET_CONTAINER_multihashmap_put (peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+                       GNUNET_CONTAINER_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
        }
 
        ats = (struct GNUNET_ATS_Information *) &tm[1];
@@ -167,10 +253,10 @@ GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
                        value = htonl (ats[c].value);
                        switch (type) {
                                case GNUNET_ATS_QUALITY_NET_DELAY:
-                                       set_delay (tmp, &tm->peer, ntohs (tm->direction), value);
+                                       set_delay (tmp, &tm->peer, direction, value);
                                        break;
                                case GNUNET_ATS_QUALITY_NET_DISTANCE:
-                                       set_distance (tmp, &tm->peer, ntohs (tm->direction), value);
+                                       set_distance (tmp, &tm->peer, direction, value);
                                        break;
                                default:
                                        break;
@@ -211,7 +297,7 @@ GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg
        struct DelayQueueEntry *dqe;
        struct GNUNET_TIME_Relative delay;
 
-       if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &target->hashPubKey)))
+       if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
        {
                        /* Manipulate here */
                        /* Delay */
@@ -234,28 +320,61 @@ GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg
                                        return;
                        }
        }
+       else if (man_handle.delay_send.rel_value != 0)
+       {
+                       /* We have a delay */
+                       delay = man_handle.delay_send;
+                       dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
+                       dqe->tmp = tmp;
+                       dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
+                       dqe->cont = cont;
+                       dqe->cont_cls = cont_cls;
+                       dqe->msg = &dqe[1];
+                       dqe->msg_size = msg_size;
+                       dqe->timeout = timeout;
+                       memcpy (dqe->msg, msg, msg_size);
+                       GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
+                       if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
+                               tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
+                       return;
+       }
+
        /* Normal sending */
        GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
 }
 
 struct GNUNET_TIME_Relative
-GST_manipulation_recv (void *cls, const struct GNUNET_PeerIdentity *peer,
+GST_manipulation_recv (void *cls,
+               const struct GNUNET_PeerIdentity *peer,
     const struct GNUNET_MessageHeader *message,
-    const struct GNUNET_ATS_Information *ats,
-    uint32_t ats_count, struct Session *session,
+    struct Session *session,
     const char *sender_address,
     uint16_t sender_address_len)
 {
        struct TM_Peer *tmp;
-       int d;
-       struct GNUNET_ATS_Information ats_new[ats_count];
-       struct GNUNET_TIME_Relative q_delay;
+       //int d;
+       //struct GNUNET_ATS_Information ats_new[ats_count];
+       struct GNUNET_TIME_Relative quota_delay;
        struct GNUNET_TIME_Relative m_delay;
 
+       if (man_handle.delay_recv.rel_value > GNUNET_TIME_UNIT_ZERO.rel_value)
+               m_delay = man_handle.delay_recv; /* Global delay */
+       else
+               m_delay = GNUNET_TIME_UNIT_ZERO;
+
+#if 0
        for (d = 0; d < ats_count; d++)
+       {
+               ats_new[d] = ats[d];
+               if ((ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) &&
+                               (man_handle.distance_recv > 0))
+                       ats_new[d].value = htonl(man_handle.distance_recv); /* Global inbound distance */
+       }
+#endif
 
-       if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey)))
+       if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
        {
+#if 0
                        /* Manipulate distance */
                        for (d = 0; d < ats_count; d++)
                        {
@@ -265,35 +384,54 @@ GST_manipulation_recv (void *cls, const struct GNUNET_PeerIdentity *peer,
                                                 (UINT32_MAX != tmp->metrics[TM_RECEIVE][DISTANCE]))
                                                        ats_new[d].value = htonl(tmp->metrics[TM_RECEIVE][DISTANCE]);
                        }
+#endif
                        /* Manipulate receive delay */
                        if (UINT32_MAX != tmp->metrics[TM_RECEIVE][DELAY])
-                       {
-                                       m_delay.rel_value = tmp->metrics[TM_RECEIVE][DELAY];
-                                       q_delay = GST_receive_callback (cls, peer, message, &ats_new[0], ats_count,
-                                                       session, sender_address, sender_address_len);
-
-                                       if (q_delay.rel_value >= m_delay.rel_value)
-                                       {
-                                                       return q_delay;
-                                       }
-                                       else
-                                       {
-                                                       return m_delay;
-                                       }
-                       }
-                       else
-                               return GST_receive_callback (cls, peer, message, &ats_new[0], ats_count,
-                                               session, sender_address, sender_address_len);
+                                       m_delay.rel_value = tmp->metrics[TM_RECEIVE][DELAY]; /* Peer specific delay */
        }
 
-       return GST_receive_callback (cls, peer, message, ats, ats_count,
+       quota_delay = GST_receive_callback (cls, peer, message,
                        session, sender_address, sender_address_len);
+       if (quota_delay.rel_value > m_delay.rel_value)
+               return quota_delay;
+       else
+               return m_delay;
+
 }
 
 void
-GST_manipulation_init ()
+GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
 {
-       peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+
+       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
+                       "transport", "MANIPULATE_DISTANCE_IN", &man_handle.distance_recv))
+               GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting inbound distance_in to %u\n",
+                               (unsigned long long) man_handle.distance_recv);
+       else
+               man_handle.distance_recv = 0;
+
+       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
+                       "transport", "MANIPULATE_DISTANCE_OUT", &man_handle.distance_send))
+               GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting outbound distance_in to %u\n",
+                               (unsigned long long) man_handle.distance_send);
+       else
+               man_handle.distance_send = 0;
+
+       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
+                       "transport", "MANIPULATE_DELAY_IN", &man_handle.delay_recv))
+               GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying inbound traffic for %llu ms\n",
+                               (unsigned long long) man_handle.delay_recv.rel_value);
+       else
+               man_handle.delay_recv.rel_value = 0;
+
+       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
+                       "transport", "MANIPULATE_DELAY_OUT", &man_handle.delay_send))
+               GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying outbound traffic for %llu ms\n",
+                       (unsigned long long) man_handle.delay_send.rel_value);
+       else
+               man_handle.delay_send.rel_value = 0;
+
+       man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
 }
 
 int free_tmps (void *cls,
@@ -305,7 +443,7 @@ int free_tmps (void *cls,
        if (NULL != value)
        {
                        struct TM_Peer *tmp = (struct TM_Peer *) value;
-                       GNUNET_CONTAINER_multihashmap_remove (peers, key, value);
+                       GNUNET_CONTAINER_multihashmap_remove (man_handle.peers, key, value);
                        next = tmp->send_head;
                        while (NULL != (dqe = next))
                        {
@@ -326,10 +464,10 @@ int free_tmps (void *cls,
 void
 GST_manipulation_stop ()
 {
-       GNUNET_CONTAINER_multihashmap_iterate (peers, &free_tmps,NULL);
+       GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
 
-       GNUNET_CONTAINER_multihashmap_destroy (peers);
-       peers = NULL;
+       GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
+       man_handle.peers = NULL;
 }