diff options
Diffstat (limited to 'src/transport/gnunet-service-transport_manipulation.c')
-rw-r--r-- | src/transport/gnunet-service-transport_manipulation.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/src/transport/gnunet-service-transport_manipulation.c b/src/transport/gnunet-service-transport_manipulation.c new file mode 100644 index 0000000..34c8ab1 --- /dev/null +++ b/src/transport/gnunet-service-transport_manipulation.c @@ -0,0 +1,336 @@ +/* + This file is part of GNUnet. + (C) 2010,2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/gnunet-service-transport_manipulation.c + * @brief transport component manipulation traffic for simulation + * @author Christian Grothoff + * @author Matthias Wachs + */ +#include "platform.h" +#include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport_clients.h" +#include "gnunet-service-transport_hello.h" +#include "gnunet-service-transport_neighbours.h" +#include "gnunet-service-transport_plugins.h" +#include "gnunet-service-transport_validation.h" +#include "gnunet-service-transport.h" +#include "transport.h" + +static struct GNUNET_CONTAINER_MultiHashMap *peers; + +#define DELAY 0 +#define DISTANCE 1 + +struct TM_Peer; + +struct DelayQueueEntry +{ + struct DelayQueueEntry *prev; + struct DelayQueueEntry *next; + struct TM_Peer *tmp; + struct GNUNET_TIME_Absolute sent_at; + void *msg; + size_t msg_size; + struct GNUNET_TIME_Relative timeout; + GST_NeighbourSendContinuation cont; + void *cont_cls; +}; + +struct TM_Peer +{ + struct GNUNET_PeerIdentity peer; + uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount]; + GNUNET_SCHEDULER_TaskIdentifier send_delay_task; + struct DelayQueueEntry *send_head; + struct DelayQueueEntry *send_tail; +}; + + + +static void +set_delay(struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value) +{ + uint32_t val; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n", + "DELAY", GNUNET_i2s(peer), + (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value); + + if (UINT32_MAX == value) + val = UINT32_MAX - 1; /* prevent overflow */ + else if (0 == value) + val = UINT32_MAX; /* disable */ + else + val = value; + + switch (direction) { + case TM_BOTH: + tmp->metrics[TM_SEND][DELAY] = val; + tmp->metrics[TM_RECEIVE][DELAY] = val; + break; + case TM_SEND: + tmp->metrics[TM_SEND][DELAY] = val; + break; + case TM_RECEIVE: + tmp->metrics[TM_RECEIVE][DELAY] = val; + break; + default: + break; + } + +} + +static void +set_distance (struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value) +{ + uint32_t val; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n", + "DISTANCE", GNUNET_i2s(peer), + (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value); + + if (UINT32_MAX == value) + val = UINT32_MAX - 1; /* prevent overflow */ + else if (0 == value) + val = UINT32_MAX; /* disable */ + else + val = value; + + switch (direction) { + case TM_BOTH: + tmp->metrics[TM_SEND][DISTANCE] = val; + tmp->metrics[TM_RECEIVE][DISTANCE] = val; + break; + case TM_SEND: + tmp->metrics[TM_SEND][DISTANCE] = val; + break; + case TM_RECEIVE: + tmp->metrics[TM_RECEIVE][DISTANCE] = val; + break; + default: + break; + } +} + +void +GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message; + struct GNUNET_ATS_Information *ats; + struct TM_Peer *tmp; + uint32_t type; + uint32_t value; + int c; + int c2; + + if (0 == ntohs (tm->ats_count)) + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + + 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))) + { + tmp = GNUNET_malloc (sizeof (struct TM_Peer)); + tmp->peer = (tm->peer); + for (c = 0; c < TM_BOTH; c++) + { + for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++) + { + tmp->metrics[c][c2] = UINT32_MAX; + } + } + GNUNET_CONTAINER_multihashmap_put (peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); + } + + 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: + set_delay (tmp, &tm->peer, ntohs (tm->direction), value); + break; + case GNUNET_ATS_QUALITY_NET_DISTANCE: + set_distance (tmp, &tm->peer, ntohs (tm->direction), value); + break; + default: + break; + } + } + + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + +static void +send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct DelayQueueEntry *dqe = cls; + struct DelayQueueEntry *next; + struct TM_Peer *tmp = dqe->tmp; + struct GNUNET_TIME_Relative delay; + tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe); + GST_neighbours_send (&tmp->peer, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls); + + next = tmp->send_head; + if (NULL != next) + { + /* More delayed messages */ + delay = GNUNET_TIME_absolute_get_remaining (next->sent_at); + tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe); + } + + GNUNET_free (dqe); +} + +void +GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg, + size_t msg_size, struct GNUNET_TIME_Relative timeout, + GST_NeighbourSendContinuation cont, void *cont_cls) +{ + struct TM_Peer *tmp; + struct DelayQueueEntry *dqe; + struct GNUNET_TIME_Relative delay; + + if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &target->hashPubKey))) + { + /* Manipulate here */ + /* Delay */ + if (UINT32_MAX != tmp->metrics[TM_SEND][DELAY]) + { + /* We have a delay */ + delay.rel_value = tmp->metrics[TM_SEND][DELAY]; + 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, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, 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; + struct GNUNET_TIME_Relative m_delay; + + for (d = 0; d < ats_count; d++) + + if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey))) + { + /* Manipulate distance */ + for (d = 0; d < ats_count; d++) + { + ats_new[d] = ats[d]; + /* Set distance */ + if ((ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) && + (UINT32_MAX != tmp->metrics[TM_RECEIVE][DISTANCE])) + ats_new[d].value = htonl(tmp->metrics[TM_RECEIVE][DISTANCE]); + } + /* 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); + } + + return GST_receive_callback (cls, peer, message, ats, ats_count, + session, sender_address, sender_address_len); +} + +void +GST_manipulation_init () +{ + peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); +} + +int free_tmps (void *cls, + const struct GNUNET_HashCode * key, + void *value) +{ + struct DelayQueueEntry *dqe; + struct DelayQueueEntry *next; + if (NULL != value) + { + struct TM_Peer *tmp = (struct TM_Peer *) value; + GNUNET_CONTAINER_multihashmap_remove (peers, key, value); + next = tmp->send_head; + while (NULL != (dqe = next)) + { + next = dqe->next; + GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe); + GNUNET_free (dqe); + } + if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task) + { + GNUNET_SCHEDULER_cancel (tmp->send_delay_task); + tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (tmp); + } + return GNUNET_OK; +} + +void +GST_manipulation_stop () +{ + GNUNET_CONTAINER_multihashmap_iterate (peers, &free_tmps,NULL); + + GNUNET_CONTAINER_multihashmap_destroy (peers); + peers = NULL; +} + + +/* end of file gnunet-service-transport_manipulation.c */ |