2 This file is part of GNUnet.
3 (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
46 * Struct containing information about manipulations to a specific peer
53 struct PropManipulationEntry
58 struct PropManipulationEntry *next;
63 struct PropManipulationEntry *prev;
73 uint32_t metrics[TM_BOTH];
78 * Struct containing information about manipulations to a specific peer
85 struct GNUNET_PeerIdentity peer;
87 struct PropManipulationEntry *head;
88 struct PropManipulationEntry *tail;
91 * Peer specific manipulation metrics
93 uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
96 * Task to schedule delayed sendding
98 GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
101 * Send queue DLL head
103 struct DelayQueueEntry *send_head;
106 * Send queue DLL tail
108 struct DelayQueueEntry *send_tail;
112 struct GST_ManipulationHandle
115 * Hashmap contain all peers currently manipulated
117 struct GNUNET_CONTAINER_MultiHashMap *peers;
120 * Peer containing information for general manipulation
122 struct TM_Peer general;
128 * Entry in the delay queue for an outbound delayed message
130 struct DelayQueueEntry
135 struct DelayQueueEntry *prev;
140 struct DelayQueueEntry *next;
143 * Peer this entry is belonging to
144 * if (NULL == tmp): enqueued in generic DLL and scheduled by generic_send_delay_task
145 * else: enqueued in tmp->send_head and tmp->send_tail and scheduled by tmp->send_delay_task
152 struct GNUNET_PeerIdentity id;
155 * Absolute time when to send
157 struct GNUNET_TIME_Absolute sent_at;
172 struct GNUNET_TIME_Relative timeout;
175 * Transports send continuation
177 GST_NeighbourSendContinuation cont;
180 * Transports send continuation cls
185 struct GST_ManipulationHandle man_handle;
188 * DLL head for delayed messages based on general delay
190 struct DelayQueueEntry *generic_dqe_head;
193 * DLL tail for delayed messages based on general delay
195 struct DelayQueueEntry *generic_dqe_tail;
198 * Task to schedule delayed sending based on general delay
200 GNUNET_SCHEDULER_TaskIdentifier generic_send_delay_task;
203 set_metric (struct TM_Peer *dest, int direction, uint32_t type, uint32_t value)
205 struct PropManipulationEntry *cur;
206 for (cur = dest->head; NULL != cur; cur = cur->next)
208 if (cur->type == type)
213 cur = GNUNET_malloc (sizeof (struct PropManipulationEntry));
214 GNUNET_CONTAINER_DLL_insert (dest->head, dest->tail, cur);
216 cur->metrics[TM_SEND] = UINT32_MAX;
217 cur->metrics[TM_RECEIVE] = UINT32_MAX;
223 cur->metrics[TM_SEND] = value;
224 cur->metrics[TM_RECEIVE] = value;
227 cur->metrics[TM_SEND] = value;
230 cur->metrics[TM_RECEIVE] = value;
239 find_metric (struct TM_Peer *dest, uint32_t type, int direction)
241 struct PropManipulationEntry *cur;
243 for (cur = dest->head; NULL != cur; cur = cur->next)
245 if (cur->type == type)
246 return cur->metrics[direction];
253 * Clean up metrics for a peer
257 free_metric (struct TM_Peer *dest)
259 struct PropManipulationEntry *cur;
260 struct PropManipulationEntry *next;
262 for (cur = dest->head; NULL != cur; cur = next)
265 GNUNET_CONTAINER_DLL_remove (dest->head, dest->tail, cur);
272 * Set traffic metric to manipulate
275 * @param client client sending message
276 * @param message containing information
279 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
280 const struct GNUNET_MessageHeader *message)
282 struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
283 struct GNUNET_PeerIdentity dummy;
284 struct GNUNET_ATS_Information *ats;
292 if (0 == ntohs (tm->ats_count))
293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
296 switch (ntohs(tm->direction)) {
301 direction = TM_RECEIVE;
310 memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
311 if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
315 ats = (struct GNUNET_ATS_Information *) &tm[1];
316 for (c = 0; c < ntohs (tm->ats_count); c++)
318 type = htonl (ats[c].type);
319 value = htonl (ats[c].value);
320 set_metric (&man_handle.general, direction, type, value);
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
326 GNUNET_i2s(&tm->peer));
328 if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
330 tmp = GNUNET_malloc (sizeof (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_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
342 ats = (struct GNUNET_ATS_Information *) &tm[1];
343 for (c = 0; c < ntohs (tm->ats_count); c++)
345 type = htonl (ats[c].type);
346 value = htonl (ats[c].value);
347 set_metric (tmp, direction, type, value);
350 GNUNET_SERVER_receive_done (client, GNUNET_OK);
354 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
356 struct DelayQueueEntry *dqe = cls;
357 struct DelayQueueEntry *next;
358 struct TM_Peer *tmp = dqe->tmp;
359 struct GNUNET_TIME_Relative delay;
363 GNUNET_break (GNUNET_YES == GST_neighbours_test_connected (&dqe->id));
364 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
365 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
366 GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
368 next = tmp->send_head;
371 /* More delayed messages */
372 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
373 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, next);
378 /* Remove from generic queue */
379 GNUNET_break (GNUNET_YES == GST_neighbours_test_connected (&dqe->id));
380 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
381 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, dqe);
382 GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
383 next = generic_dqe_head;
386 /* More delayed messages */
387 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
388 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, next);
396 * Adapter function between transport's send function and transport plugins
398 * @param target the peer the message to send to
399 * @param msg the message received
400 * @param msg_size message size
401 * @param timeout timeout
402 * @param cont the continuation to call after sending
403 * @param cont_cls cls for continuation
406 GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg,
407 size_t msg_size, struct GNUNET_TIME_Relative timeout,
408 GST_NeighbourSendContinuation cont, void *cont_cls)
411 struct DelayQueueEntry *dqe;
412 struct GNUNET_TIME_Relative delay;
414 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
416 GNUNET_break (GNUNET_YES == GST_neighbours_test_connected(target));
417 /* Manipulate here */
419 if (UINT32_MAX != find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
421 /* We have a delay */
422 delay.rel_value_us = find_metric (tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
423 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
426 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
428 dqe->cont_cls = cont_cls;
430 dqe->msg_size = msg_size;
431 dqe->timeout = timeout;
432 memcpy (dqe->msg, msg, msg_size);
433 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
434 if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
435 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437 "Delaying %u byte message to peer `%s' with generic delay for %ms\n",
438 msg_size, GNUNET_i2s (target),
439 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
443 else if (UINT32_MAX != find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
445 GNUNET_break (GNUNET_YES == GST_neighbours_test_connected(target));
446 /* We have a delay */
447 delay.rel_value_us = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
448 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
451 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
453 dqe->cont_cls = cont_cls;
455 dqe->msg_size = msg_size;
456 dqe->timeout = timeout;
457 memcpy (dqe->msg, msg, msg_size);
458 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head, generic_dqe_tail, dqe);
459 if (GNUNET_SCHEDULER_NO_TASK == generic_send_delay_task)
461 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
465 msg_size, GNUNET_i2s (target),
466 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
471 GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
476 * Function that will be called to manipulate ATS information according to
477 * current manipulation settings
479 * @param peer the peer
480 * @param address binary address
481 * @param session the session
482 * @param ats the ats information
483 * @param ats_count the number of ats information
485 struct GNUNET_ATS_Information *
486 GST_manipulation_manipulate_metrics (const struct GNUNET_PeerIdentity *peer,
487 const struct GNUNET_HELLO_Address *address,
488 struct Session *session,
489 const struct GNUNET_ATS_Information *ats,
492 struct GNUNET_ATS_Information *ats_new = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *ats_count);
497 tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey);
499 for (d = 0; d < ats_count; d++)
504 m_tmp = find_metric (tmp, ntohl(ats[d].type), TM_RECEIVE);
505 g_tmp = find_metric (&man_handle.general, ntohl(ats[d].type), TM_RECEIVE);
507 if (UINT32_MAX != g_tmp)
508 ats_new[d].value = htonl(g_tmp);
509 if (UINT32_MAX != m_tmp)
510 ats_new[d].value = htonl(m_tmp);
518 * Adapter function between transport plugins and transport receive function
519 * manipulation delays for next send.
521 * @param cls the closure for transport
522 * @param peer the peer the message was received from
523 * @param message the message received
524 * @param session the session the message was received on
525 * @param sender_address the sender address
526 * @param sender_address_len the length of the sender address
527 * @return manipulated delay for next receive
529 struct GNUNET_TIME_Relative
530 GST_manipulation_recv (void *cls,
531 const struct GNUNET_PeerIdentity *peer,
532 const struct GNUNET_MessageHeader *message,
533 struct Session *session,
534 const char *sender_address,
535 uint16_t sender_address_len)
538 uint32_t p_recv_delay;
539 uint32_t g_recv_delay;
540 struct GNUNET_TIME_Relative quota_delay;
541 struct GNUNET_TIME_Relative m_delay;
543 g_recv_delay = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
544 if ((g_recv_delay >= GNUNET_TIME_UNIT_ZERO.rel_value_us) && (UINT32_MAX != g_recv_delay))
545 m_delay.rel_value_us = g_recv_delay; /* Global delay */
547 m_delay = GNUNET_TIME_UNIT_ZERO;
549 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
551 /* Manipulate receive delay */
552 p_recv_delay = find_metric (tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
553 if (UINT32_MAX != p_recv_delay)
554 m_delay.rel_value_us = p_recv_delay; /* Peer specific delay */
557 quota_delay = GST_receive_callback (cls, peer, message,
558 session, sender_address, sender_address_len);
560 if (quota_delay.rel_value_us > m_delay.rel_value_us)
561 m_delay = quota_delay;
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "Delaying next receive for peer `%s' for %s\n",
566 GNUNET_STRINGS_relative_time_to_string (m_delay, GNUNET_YES));
573 * Initialize traffic manipulation
575 * @param GST_cfg configuration handle
578 GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
580 unsigned long long tmp;
581 struct GNUNET_TIME_Relative delay;
583 if ( (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
585 "MANIPULATE_DISTANCE_IN",
589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
590 "Setting inbound distance_in to %llu\n",
591 (unsigned long long) tmp);
592 set_metric (&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
595 if ( (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
597 "MANIPULATE_DISTANCE_OUT",
601 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
602 "Setting outbound distance_in to %llu\n",
603 (unsigned long long) tmp);
604 set_metric (&man_handle.general, TM_SEND,
605 GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
608 if ( (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
610 "MANIPULATE_DELAY_IN",
612 (delay.rel_value_us > 0) )
614 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
615 "Delaying inbound traffic for %s\n",
616 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
617 set_metric (&man_handle.general, TM_RECEIVE,
618 GNUNET_ATS_QUALITY_NET_DELAY,
621 if ( (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
623 "MANIPULATE_DELAY_OUT",
625 (delay.rel_value_us > 0) )
627 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
628 "Delaying outbound traffic for %s\n",
629 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
630 set_metric (&man_handle.general,
632 GNUNET_ATS_QUALITY_NET_DELAY,
635 man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
640 free_tmps (void *cls,
641 const struct GNUNET_HashCode * key,
644 struct DelayQueueEntry *dqe;
645 struct DelayQueueEntry *next;
649 struct TM_Peer *tmp = (struct TM_Peer *) value;
651 if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (man_handle.peers, key, value))
654 next = tmp->send_head;
655 while (NULL != (dqe = next))
658 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
659 if (NULL != dqe->cont)
660 dqe->cont (dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
663 if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
665 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
666 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
675 * Notify manipulation about disconnect so it can discard queued messages
677 * @param peer the disconnecting peer
680 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
683 struct DelayQueueEntry *dqe;
684 struct DelayQueueEntry *next;
686 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
688 next = tmp->send_head;
689 while (NULL != (dqe = next))
692 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
693 if (NULL != dqe->cont)
694 dqe->cont (dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
698 else if (UINT32_MAX != find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
700 next = generic_dqe_head;
701 while (NULL != (dqe = next))
704 if (0 == memcmp (peer, &dqe->id, sizeof (dqe->id)))
706 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, dqe);
707 if (NULL != dqe->cont)
708 dqe->cont (dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
712 if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
714 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
715 if (NULL != generic_dqe_head)
716 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (
717 GNUNET_TIME_absolute_get_remaining(generic_dqe_head->sent_at),
718 &send_delayed, generic_dqe_head);
725 * Stop traffic manipulation
728 GST_manipulation_stop ()
730 struct DelayQueueEntry *cur;
731 struct DelayQueueEntry *next;
732 GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
733 GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
735 next = generic_dqe_head;
736 while (NULL != (cur = next))
739 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, cur);
740 if (NULL != cur->cont)
741 cur->cont (cur->cont_cls, GNUNET_SYSERR, cur->msg_size, 0);
744 if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
746 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
747 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
750 free_metric (&man_handle.general);
751 man_handle.peers = NULL;
755 /* end of file gnunet-service-transport_manipulation.c */