2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport_manipulation.c
23 * @brief transport component manipulation traffic for simulation
24 * @author Christian Grothoff
25 * @author Matthias Wachs
28 #include "gnunet-service-transport_blacklist.h"
29 #include "gnunet-service-transport_clients.h"
30 #include "gnunet-service-transport_hello.h"
31 #include "gnunet-service-transport_neighbours.h"
32 #include "gnunet-service-transport_plugins.h"
33 #include "gnunet-service-transport_validation.h"
34 #include "gnunet-service-transport.h"
35 #include "transport.h"
37 enum TRAFFIC_METRIC_DIRECTION
39 TM_SEND = 0, TM_RECEIVE = 1, TM_BOTH = 2
44 * Struct containing information about manipulations to a specific peer
51 struct PropManipulationEntry
56 struct PropManipulationEntry *next;
61 struct PropManipulationEntry *prev;
71 uint32_t metrics[TM_BOTH];
76 * Struct containing information about manipulations to a specific peer
83 struct GNUNET_PeerIdentity peer;
85 struct PropManipulationEntry *head;
86 struct PropManipulationEntry *tail;
89 * Peer specific manipulation metrics
91 uint32_t metrics[TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
94 * Task to schedule delayed sendding
96 struct GNUNET_SCHEDULER_Task * send_delay_task;
101 struct DelayQueueEntry *send_head;
104 * Send queue DLL tail
106 struct DelayQueueEntry *send_tail;
110 struct GST_ManipulationHandle
113 * Hashmap contain all peers currently manipulated
115 struct GNUNET_CONTAINER_MultiPeerMap *peers;
118 * Peer containing information for general manipulation
120 struct TM_Peer general;
124 * Entry in the delay queue for an outbound delayed message
126 struct DelayQueueEntry
131 struct DelayQueueEntry *prev;
136 struct DelayQueueEntry *next;
139 * Peer this entry is belonging to
140 * if (NULL == tmp): enqueued in generic DLL and scheduled by generic_send_delay_task
141 * else: enqueued in tmp->send_head and tmp->send_tail and scheduled by tmp->send_delay_task
148 struct GNUNET_PeerIdentity id;
151 * Absolute time when to send
153 struct GNUNET_TIME_Absolute sent_at;
168 struct GNUNET_TIME_Relative timeout;
171 * Transports send continuation
173 GST_NeighbourSendContinuation cont;
176 * Transports send continuation cls
181 struct GST_ManipulationHandle man_handle;
184 * DLL head for delayed messages based on general delay
186 struct DelayQueueEntry *generic_dqe_head;
189 * DLL tail for delayed messages based on general delay
191 struct DelayQueueEntry *generic_dqe_tail;
194 * Task to schedule delayed sending based on general delay
196 struct GNUNET_SCHEDULER_Task * generic_send_delay_task;
200 set_metric(struct TM_Peer *dest, int direction, uint32_t type, uint32_t value)
202 struct PropManipulationEntry *cur;
203 for (cur = dest->head; NULL != cur; cur = cur->next)
205 if (cur->type == type)
210 cur = GNUNET_new (struct PropManipulationEntry);
211 GNUNET_CONTAINER_DLL_insert(dest->head, dest->tail, cur);
213 cur->metrics[TM_SEND] = UINT32_MAX;
214 cur->metrics[TM_RECEIVE] = UINT32_MAX;
220 cur->metrics[TM_SEND] = value;
221 cur->metrics[TM_RECEIVE] = value;
224 cur->metrics[TM_SEND] = value;
227 cur->metrics[TM_RECEIVE] = value;
236 find_metric(struct TM_Peer *dest, uint32_t type, int direction)
238 struct PropManipulationEntry *cur;
240 for (cur = dest->head; NULL != cur; cur = cur->next)
242 if (cur->type == type)
243 return cur->metrics[direction];
251 * Clean up metrics for a peer
254 free_metric(struct TM_Peer *dest)
256 struct PropManipulationEntry *cur;
257 struct PropManipulationEntry *next;
259 for (cur = dest->head; NULL != cur; cur = next)
262 GNUNET_CONTAINER_DLL_remove(dest->head, dest->tail, cur);
269 * Set traffic metric to manipulate
272 * @param client client sending message
273 * @param message containing information
276 GST_manipulation_set_metric(void *cls, struct GNUNET_SERVER_Client *client,
277 const struct GNUNET_MessageHeader *message)
279 struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
280 struct GNUNET_PeerIdentity dummy;
281 struct GNUNET_ATS_Information *ats;
289 if (0 == ntohs(tm->ats_count))
290 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
293 switch (ntohs(tm->direction))
299 direction = TM_RECEIVE;
308 memset(&dummy, '\0', sizeof(struct GNUNET_PeerIdentity));
309 if (0 == memcmp(&tm->peer, &dummy, sizeof(struct GNUNET_PeerIdentity)))
311 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
312 "Received traffic metrics for all peers \n");
314 ats = (struct GNUNET_ATS_Information *) &tm[1];
315 for (c = 0; c < ntohs(tm->ats_count); c++)
317 type = htonl(ats[c].type);
318 value = htonl(ats[c].value);
319 set_metric(&man_handle.general, direction, type, value);
324 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
325 "Received traffic metrics for peer `%s'\n", GNUNET_i2s(&tm->peer));
328 == (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, &tm->peer)))
330 tmp = GNUNET_new (struct TM_Peer);
331 tmp->peer = (tm->peer);
332 for (c = 0; c < TM_BOTH; c++)
334 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
336 tmp->metrics[c][c2] = UINT32_MAX;
339 GNUNET_CONTAINER_multipeermap_put(man_handle.peers, &tm->peer, tmp,
340 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
343 ats = (struct GNUNET_ATS_Information *) &tm[1];
344 for (c = 0; c < ntohs(tm->ats_count); c++)
346 type = htonl(ats[c].type);
347 value = htonl(ats[c].value);
348 set_metric(tmp, direction, type, value);
351 GNUNET_SERVER_receive_done(client, GNUNET_OK);
356 send_delayed(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
358 struct DelayQueueEntry *dqe = cls;
359 struct DelayQueueEntry *next;
360 struct TM_Peer *tmp = dqe->tmp;
361 struct GNUNET_TIME_Relative delay;
365 GNUNET_break (GNUNET_YES ==
366 GST_neighbours_test_connected (&dqe->id));
367 tmp->send_delay_task = NULL;
368 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
371 GST_neighbours_send (&dqe->id,
378 next = tmp->send_head;
381 /* More delayed messages */
382 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
383 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
384 &send_delayed, next);
389 /* Remove from generic queue */
390 GNUNET_break(GNUNET_YES == GST_neighbours_test_connected (&dqe->id));
391 generic_send_delay_task = NULL;
392 GNUNET_CONTAINER_DLL_remove(generic_dqe_head, generic_dqe_tail, dqe);
393 GST_neighbours_send(&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout,
394 dqe->cont, dqe->cont_cls);
395 next = generic_dqe_head;
398 /* More delayed messages */
399 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
400 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
401 &send_delayed, next);
409 * Adapter function between transport's send function and transport plugins.
410 * Delays message transmission if an artificial delay is configured.
412 * @param target the peer the message to send to
413 * @param msg the message received
414 * @param msg_size message size
415 * @param timeout timeout
416 * @param cont the continuation to call after sending
417 * @param cont_cls cls for @a cont
420 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
423 struct GNUNET_TIME_Relative timeout,
424 GST_NeighbourSendContinuation cont,
428 struct DelayQueueEntry *dqe;
429 struct GNUNET_TIME_Relative delay;
432 do_delay = GNUNET_NO;
434 GNUNET_CONTAINER_multipeermap_get (man_handle.peers,
437 GNUNET_break (GNUNET_YES ==
438 GST_neighbours_test_connected(target));
439 /* check for peer-specific delay */
442 GNUNET_ATS_QUALITY_NET_DELAY,
445 /* We have a delay */
446 delay.rel_value_us = find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY,
448 do_delay = GNUNET_YES;
451 else if (UINT32_MAX !=
452 find_metric(&man_handle.general,
453 GNUNET_ATS_QUALITY_NET_DELAY,
456 GNUNET_break (GNUNET_YES ==
457 GST_neighbours_test_connected (target));
458 /* We have a delay */
459 delay.rel_value_us = find_metric (&man_handle.general,
460 GNUNET_ATS_QUALITY_NET_DELAY,
462 do_delay = GNUNET_YES;
464 if (GNUNET_NO == do_delay)
467 GST_neighbours_send (target,
474 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
477 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
479 dqe->cont_cls = cont_cls;
481 dqe->msg_size = msg_size;
482 dqe->timeout = timeout;
488 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
491 if (NULL == generic_send_delay_task)
492 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
498 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
501 if (NULL == tmp->send_delay_task)
502 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
510 GNUNET_STRINGS_relative_time_to_string (delay,
516 * Function that will be called to manipulate ATS information according to
517 * current manipulation settings
519 * @param peer the peer
520 * @param address binary address
521 * @param session the session
522 * @param ats the ats information
523 * @param ats_count the number of ats information
525 struct GNUNET_ATS_Information *
526 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
527 struct Session *session,
528 const struct GNUNET_ATS_Information *ats,
531 const struct GNUNET_PeerIdentity *peer = &address->peer;
532 struct GNUNET_ATS_Information *ats_new;
540 ats_new = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) * ats_count);
541 tmp = GNUNET_CONTAINER_multipeermap_get (man_handle.peers, peer);
542 for (d = 0; d < ats_count; d++)
547 m_tmp = find_metric (tmp, ntohl(ats[d].type),
549 g_tmp = find_metric (&man_handle.general,
553 if (UINT32_MAX != g_tmp)
554 ats_new[d].value = htonl(g_tmp);
555 if (UINT32_MAX != m_tmp)
556 ats_new[d].value = htonl(m_tmp);
563 * Adapter function between transport plugins and transport receive function
564 * manipulation delays for next send.
566 * @param cls the closure for transport
567 * @param address the address and the peer the message was received from
568 * @param message the message received
569 * @param session the session the message was received on
570 * @return manipulated delay for next receive
572 struct GNUNET_TIME_Relative
573 GST_manipulation_recv (void *cls,
574 const struct GNUNET_HELLO_Address *address,
575 struct Session *session,
576 const struct GNUNET_MessageHeader *message)
579 uint32_t p_recv_delay;
580 uint32_t g_recv_delay;
581 struct GNUNET_TIME_Relative quota_delay;
582 struct GNUNET_TIME_Relative m_delay;
584 g_recv_delay = find_metric(&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY,
586 if ((g_recv_delay >= GNUNET_TIME_UNIT_ZERO.rel_value_us)
587 && (UINT32_MAX != g_recv_delay))
588 m_delay.rel_value_us = g_recv_delay; /* Global delay */
590 m_delay = GNUNET_TIME_UNIT_ZERO;
592 if (NULL != (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, &address->peer)))
594 /* Manipulate receive delay */
595 p_recv_delay = find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
596 if (UINT32_MAX != p_recv_delay)
597 m_delay.rel_value_us = p_recv_delay; /* Peer specific delay */
600 quota_delay = GST_receive_callback(cls, address, session, message);
602 if (quota_delay.rel_value_us > m_delay.rel_value_us)
603 m_delay = quota_delay;
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Delaying next receive for peer `%s' for %s\n",
607 GNUNET_i2s (&address->peer),
608 GNUNET_STRINGS_relative_time_to_string (m_delay,
615 * Initialize traffic manipulation
617 * @param GST_cfg configuration handle
620 GST_manipulation_init(const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
622 unsigned long long tmp;
623 struct GNUNET_TIME_Relative delay;
626 GNUNET_CONFIGURATION_get_value_number(GST_cfg,
628 "MANIPULATE_DISTANCE_IN",
632 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
633 "Setting inbound distance_in to %llu\n",
634 (unsigned long long) tmp);
635 set_metric (&man_handle.general,
637 GNUNET_ATS_QUALITY_NET_DISTANCE,
642 == GNUNET_CONFIGURATION_get_value_number(GST_cfg, "transport",
643 "MANIPULATE_DISTANCE_OUT", &tmp)) && (tmp > 0))
645 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
646 "Setting outbound distance_in to %llu\n", (unsigned long long) tmp);
647 set_metric(&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DISTANCE,
652 == GNUNET_CONFIGURATION_get_value_time(GST_cfg, "transport",
653 "MANIPULATE_DELAY_IN", &delay)) && (delay.rel_value_us > 0))
655 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
656 "Delaying inbound traffic for %s\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
657 set_metric(&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DELAY,
661 == GNUNET_CONFIGURATION_get_value_time(GST_cfg, "transport",
662 "MANIPULATE_DELAY_OUT", &delay)) && (delay.rel_value_us > 0))
664 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
665 "Delaying outbound traffic for %s\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
666 set_metric(&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DELAY,
669 man_handle.peers = GNUNET_CONTAINER_multipeermap_create(10, GNUNET_NO);
674 free_tmps (void *cls,
675 const struct GNUNET_PeerIdentity *key,
678 struct TM_Peer *tmp = value;
679 struct DelayQueueEntry *dqe;
683 GNUNET_break (GNUNET_YES ==
684 GNUNET_CONTAINER_multipeermap_remove (man_handle.peers,
688 while (NULL != (dqe = tmp->send_head))
690 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
693 if (NULL != dqe->cont)
694 dqe->cont (dqe->cont_cls,
700 if (NULL != tmp->send_delay_task)
702 GNUNET_SCHEDULER_cancel(tmp->send_delay_task);
703 tmp->send_delay_task = NULL;
711 * Notify manipulation about disconnect so it can discard queued messages
713 * @param peer the disconnecting peer
716 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
719 struct DelayQueueEntry *dqe;
720 struct DelayQueueEntry *next;
722 if (NULL != (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, peer)))
724 while (NULL != (dqe = tmp->send_head))
726 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
729 if (NULL != dqe->cont)
730 dqe->cont (dqe->cont_cls,
737 else if (UINT32_MAX != find_metric (&man_handle.general,
738 GNUNET_ATS_QUALITY_NET_DELAY,
741 next = generic_dqe_head;
742 while (NULL != (dqe = next))
745 if (0 == memcmp(peer, &dqe->id, sizeof(dqe->id)))
747 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
750 if (NULL != dqe->cont)
751 dqe->cont (dqe->cont_cls,
758 if (NULL != generic_send_delay_task)
760 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
761 generic_send_delay_task = NULL;
762 if (NULL != generic_dqe_head)
763 generic_send_delay_task
764 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(generic_dqe_head->sent_at),
773 * Stop traffic manipulation
776 GST_manipulation_stop()
778 struct DelayQueueEntry *cur;
780 GNUNET_CONTAINER_multipeermap_iterate (man_handle.peers,
783 GNUNET_CONTAINER_multipeermap_destroy (man_handle.peers);
785 while (NULL != (cur = generic_dqe_head))
787 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
790 if (NULL != cur->cont)
791 cur->cont (cur->cont_cls,
797 if (NULL != generic_send_delay_task)
799 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
800 generic_send_delay_task = NULL;
802 free_metric (&man_handle.general);
803 man_handle.peers = NULL;
806 /* end of file gnunet-service-transport_manipulation.c */