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
39 TM_SEND = 0, TM_RECEIVE = 1, TM_BOTH = 2
43 * Struct containing information about manipulations to a specific peer
50 struct PropManipulationEntry
55 struct PropManipulationEntry *next;
60 struct PropManipulationEntry *prev;
70 uint32_t metrics[TM_BOTH];
75 * Struct containing information about manipulations to a specific peer
82 struct GNUNET_PeerIdentity peer;
84 struct PropManipulationEntry *head;
85 struct PropManipulationEntry *tail;
88 * Peer specific manipulation metrics
90 uint32_t metrics[TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
93 * Task to schedule delayed sendding
95 GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
100 struct DelayQueueEntry *send_head;
103 * Send queue DLL tail
105 struct DelayQueueEntry *send_tail;
108 struct GST_ManipulationHandle
111 * Hashmap contain all peers currently manipulated
113 struct GNUNET_CONTAINER_MultiPeerMap *peers;
116 * Peer containing information for general manipulation
118 struct TM_Peer general;
122 * Entry in the delay queue for an outbound delayed message
124 struct DelayQueueEntry
129 struct DelayQueueEntry *prev;
134 struct DelayQueueEntry *next;
137 * Peer this entry is belonging to
138 * if (NULL == tmp): enqueued in generic DLL and scheduled by generic_send_delay_task
139 * else: enqueued in tmp->send_head and tmp->send_tail and scheduled by tmp->send_delay_task
146 struct GNUNET_PeerIdentity id;
149 * Absolute time when to send
151 struct GNUNET_TIME_Absolute sent_at;
166 struct GNUNET_TIME_Relative timeout;
169 * Transports send continuation
171 GST_NeighbourSendContinuation cont;
174 * Transports send continuation cls
179 struct GST_ManipulationHandle man_handle;
182 * DLL head for delayed messages based on general delay
184 struct DelayQueueEntry *generic_dqe_head;
187 * DLL tail for delayed messages based on general delay
189 struct DelayQueueEntry *generic_dqe_tail;
192 * Task to schedule delayed sending based on general delay
194 GNUNET_SCHEDULER_TaskIdentifier generic_send_delay_task;
197 set_metric(struct TM_Peer *dest, int direction, uint32_t type, uint32_t value)
199 struct PropManipulationEntry *cur;
200 for (cur = dest->head; NULL != cur; cur = cur->next)
202 if (cur->type == type)
207 cur = GNUNET_new (struct PropManipulationEntry);
208 GNUNET_CONTAINER_DLL_insert(dest->head, dest->tail, cur);
210 cur->metrics[TM_SEND] = UINT32_MAX;
211 cur->metrics[TM_RECEIVE] = UINT32_MAX;
217 cur->metrics[TM_SEND] = value;
218 cur->metrics[TM_RECEIVE] = value;
221 cur->metrics[TM_SEND] = value;
224 cur->metrics[TM_RECEIVE] = value;
233 find_metric(struct TM_Peer *dest, uint32_t type, int direction)
235 struct PropManipulationEntry *cur;
237 for (cur = dest->head; NULL != cur; cur = cur->next)
239 if (cur->type == type)
240 return cur->metrics[direction];
247 * Clean up metrics for a peer
251 free_metric(struct TM_Peer *dest)
253 struct PropManipulationEntry *cur;
254 struct PropManipulationEntry *next;
256 for (cur = dest->head; NULL != cur; cur = next)
259 GNUNET_CONTAINER_DLL_remove(dest->head, dest->tail, cur);
265 * Set traffic metric to manipulate
268 * @param client client sending message
269 * @param message containing information
272 GST_manipulation_set_metric(void *cls, struct GNUNET_SERVER_Client *client,
273 const struct GNUNET_MessageHeader *message)
275 struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
276 struct GNUNET_PeerIdentity dummy;
277 struct GNUNET_ATS_Information *ats;
285 if (0 == ntohs(tm->ats_count))
286 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
289 switch (ntohs(tm->direction))
295 direction = TM_RECEIVE;
304 memset(&dummy, '\0', sizeof(struct GNUNET_PeerIdentity));
305 if (0 == memcmp(&tm->peer, &dummy, sizeof(struct GNUNET_PeerIdentity)))
307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
308 "Received traffic metrics for all peers \n");
310 ats = (struct GNUNET_ATS_Information *) &tm[1];
311 for (c = 0; c < ntohs(tm->ats_count); c++)
313 type = htonl(ats[c].type);
314 value = htonl(ats[c].value);
315 set_metric(&man_handle.general, direction, type, value);
320 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
321 "Received traffic metrics for peer `%s'\n", GNUNET_i2s(&tm->peer));
324 == (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, &tm->peer)))
326 tmp = GNUNET_new (struct TM_Peer);
327 tmp->peer = (tm->peer);
328 for (c = 0; c < TM_BOTH; c++)
330 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
332 tmp->metrics[c][c2] = UINT32_MAX;
335 GNUNET_CONTAINER_multipeermap_put(man_handle.peers, &tm->peer, tmp,
336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
339 ats = (struct GNUNET_ATS_Information *) &tm[1];
340 for (c = 0; c < ntohs(tm->ats_count); c++)
342 type = htonl(ats[c].type);
343 value = htonl(ats[c].value);
344 set_metric(tmp, direction, type, value);
347 GNUNET_SERVER_receive_done(client, GNUNET_OK);
351 send_delayed(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
353 struct DelayQueueEntry *dqe = cls;
354 struct DelayQueueEntry *next;
355 struct TM_Peer *tmp = dqe->tmp;
356 struct GNUNET_TIME_Relative delay;
360 GNUNET_break(GNUNET_YES == GST_neighbours_test_connected (&dqe->id));
361 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
362 GNUNET_CONTAINER_DLL_remove(tmp->send_head, tmp->send_tail, dqe);
363 GST_neighbours_send(&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout,
364 dqe->cont, dqe->cont_cls);
366 next = tmp->send_head;
369 /* More delayed messages */
370 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
371 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
372 &send_delayed, next);
377 /* Remove from generic queue */
378 GNUNET_break(GNUNET_YES == GST_neighbours_test_connected (&dqe->id));
379 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
380 GNUNET_CONTAINER_DLL_remove(generic_dqe_head, generic_dqe_tail, dqe);
381 GST_neighbours_send(&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout,
382 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,
389 &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;
415 != (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, target)))
417 GNUNET_break(GNUNET_YES == GST_neighbours_test_connected(target));
418 /* Manipulate here */
420 if (UINT32_MAX != find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
422 /* We have a delay */
423 delay.rel_value_us = find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY,
425 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
428 dqe->sent_at = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(),
431 dqe->cont_cls = cont_cls;
433 dqe->msg_size = msg_size;
434 dqe->timeout = timeout;
435 memcpy(dqe->msg, msg, msg_size);
436 GNUNET_CONTAINER_DLL_insert_tail(tmp->send_head, tmp->send_tail, dqe);
437 if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
438 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
440 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
441 "Delaying %u byte message to peer `%s' with generic delay for %ms\n", msg_size, GNUNET_i2s (target), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
446 != find_metric(&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY,
449 GNUNET_break(GNUNET_YES == GST_neighbours_test_connected(target));
450 /* We have a delay */
451 delay.rel_value_us = find_metric(&man_handle.general,
452 GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
453 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
456 dqe->sent_at = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(),
459 dqe->cont_cls = cont_cls;
461 dqe->msg_size = msg_size;
462 dqe->timeout = timeout;
463 memcpy(dqe->msg, msg, msg_size);
464 GNUNET_CONTAINER_DLL_insert_tail(generic_dqe_head, generic_dqe_tail, dqe);
465 if (GNUNET_SCHEDULER_NO_TASK == generic_send_delay_task)
467 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
470 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
471 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n", msg_size, GNUNET_i2s (target), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
476 GST_neighbours_send(target, msg, msg_size, timeout, cont, cont_cls);
480 * Function that will be called to manipulate ATS information according to
481 * current manipulation settings
483 * @param peer the peer
484 * @param address binary address
485 * @param session the session
486 * @param ats the ats information
487 * @param ats_count the number of ats information
489 struct GNUNET_ATS_Information *
490 GST_manipulation_manipulate_metrics(const struct GNUNET_PeerIdentity *peer,
491 const struct GNUNET_HELLO_Address *address, struct Session *session,
492 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
494 struct GNUNET_ATS_Information *ats_new =
495 GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *ats_count);
500 tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, peer);
502 for (d = 0; d < ats_count; d++)
507 m_tmp = find_metric(tmp, ntohl(ats[d].type), TM_RECEIVE);
508 g_tmp = find_metric(&man_handle.general, ntohl(ats[d].type), TM_RECEIVE);
510 if (UINT32_MAX != g_tmp)
511 ats_new[d].value = htonl(g_tmp);
512 if (UINT32_MAX != m_tmp)
513 ats_new[d].value = htonl(m_tmp);
520 * Adapter function between transport plugins and transport receive function
521 * manipulation delays for next send.
523 * @param cls the closure for transport
524 * @param address the address and the peer the message was received from
525 * @param message the message received
526 * @param session the session the message was received on
527 * @return manipulated delay for next receive
529 struct GNUNET_TIME_Relative
530 GST_manipulation_recv (void *cls,
531 const struct GNUNET_HELLO_Address *address,
532 struct Session *session,
533 const struct GNUNET_MessageHeader *message)
536 uint32_t p_recv_delay;
537 uint32_t g_recv_delay;
538 struct GNUNET_TIME_Relative quota_delay;
539 struct GNUNET_TIME_Relative m_delay;
541 g_recv_delay = find_metric(&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY,
543 if ((g_recv_delay >= GNUNET_TIME_UNIT_ZERO.rel_value_us)
544 && (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_multipeermap_get(man_handle.peers, &address->peer)))
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, address, session, message);
559 if (quota_delay.rel_value_us > m_delay.rel_value_us)
560 m_delay = quota_delay;
562 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
563 "Delaying next receive for peer `%s' for %s\n",
564 GNUNET_i2s (&address->peer),
565 GNUNET_STRINGS_relative_time_to_string (m_delay, GNUNET_YES));
571 * Initialize traffic manipulation
573 * @param GST_cfg configuration handle
576 GST_manipulation_init(const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
578 unsigned long long tmp;
579 struct GNUNET_TIME_Relative delay;
582 == GNUNET_CONFIGURATION_get_value_number(GST_cfg, "transport",
583 "MANIPULATE_DISTANCE_IN", &tmp)) && (tmp > 0))
585 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
586 "Setting inbound distance_in to %llu\n", (unsigned long long) tmp);
587 set_metric(&man_handle.general, TM_RECEIVE,
588 GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
592 == GNUNET_CONFIGURATION_get_value_number(GST_cfg, "transport",
593 "MANIPULATE_DISTANCE_OUT", &tmp)) && (tmp > 0))
595 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
596 "Setting outbound distance_in to %llu\n", (unsigned long long) tmp);
597 set_metric(&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DISTANCE,
602 == GNUNET_CONFIGURATION_get_value_time(GST_cfg, "transport",
603 "MANIPULATE_DELAY_IN", &delay)) && (delay.rel_value_us > 0))
605 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
606 "Delaying inbound traffic for %s\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
607 set_metric(&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DELAY,
611 == GNUNET_CONFIGURATION_get_value_time(GST_cfg, "transport",
612 "MANIPULATE_DELAY_OUT", &delay)) && (delay.rel_value_us > 0))
614 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
615 "Delaying outbound traffic for %s\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
616 set_metric(&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DELAY,
619 man_handle.peers = GNUNET_CONTAINER_multipeermap_create(10, GNUNET_NO);
623 free_tmps(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
625 struct DelayQueueEntry *dqe;
626 struct DelayQueueEntry *next;
630 struct TM_Peer *tmp = (struct TM_Peer *) value;
633 != GNUNET_CONTAINER_multipeermap_remove(man_handle.peers, key, value))
636 next = tmp->send_head;
637 while (NULL != (dqe = next))
640 GNUNET_CONTAINER_DLL_remove(tmp->send_head, tmp->send_tail, dqe);
641 if (NULL != dqe->cont)
642 dqe->cont(dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
645 if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
647 GNUNET_SCHEDULER_cancel(tmp->send_delay_task);
648 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
656 * Notify manipulation about disconnect so it can discard queued messages
658 * @param peer the disconnecting peer
661 GST_manipulation_peer_disconnect(const struct GNUNET_PeerIdentity *peer)
664 struct DelayQueueEntry *dqe;
665 struct DelayQueueEntry *next;
667 if (NULL != (tmp = GNUNET_CONTAINER_multipeermap_get(man_handle.peers, peer)))
669 next = tmp->send_head;
670 while (NULL != (dqe = next))
673 GNUNET_CONTAINER_DLL_remove(tmp->send_head, tmp->send_tail, dqe);
674 if (NULL != dqe->cont)
675 dqe->cont(dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
680 != find_metric(&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY,
683 next = generic_dqe_head;
684 while (NULL != (dqe = next))
687 if (0 == memcmp(peer, &dqe->id, sizeof(dqe->id)))
689 GNUNET_CONTAINER_DLL_remove(generic_dqe_head, generic_dqe_tail,
691 if (NULL != dqe->cont)
692 dqe->cont(dqe->cont_cls, GNUNET_SYSERR, dqe->msg_size, 0);
696 if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
698 GNUNET_SCHEDULER_cancel(generic_send_delay_task);
699 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
700 if (NULL != generic_dqe_head)
701 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed(
702 GNUNET_TIME_absolute_get_remaining(generic_dqe_head->sent_at),
703 &send_delayed, generic_dqe_head);
709 * Stop traffic manipulation
712 GST_manipulation_stop()
714 struct DelayQueueEntry *cur;
715 struct DelayQueueEntry *next;
716 GNUNET_CONTAINER_multipeermap_iterate(man_handle.peers, &free_tmps, NULL);
717 GNUNET_CONTAINER_multipeermap_destroy(man_handle.peers);
719 next = generic_dqe_head;
720 while (NULL != (cur = next))
723 GNUNET_CONTAINER_DLL_remove(generic_dqe_head, generic_dqe_tail, cur);
724 if (NULL != cur->cont)
725 cur->cont(cur->cont_cls, GNUNET_SYSERR, cur->msg_size, 0);
728 if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
730 GNUNET_SCHEDULER_cancel(generic_send_delay_task);
731 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
734 free_metric(&man_handle.general);
735 man_handle.peers = NULL;
738 /* end of file gnunet-service-transport_manipulation.c */