2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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_hello.h"
29 #include "gnunet-service-transport_neighbours.h"
30 #include "gnunet-service-transport_plugins.h"
31 #include "gnunet-service-transport_validation.h"
32 #include "gnunet-service-transport.h"
33 #include "transport.h"
37 * Struct containing information about manipulations to a specific peer
44 struct GNUNET_PeerIdentity peer;
47 * How long to delay incoming messages for this peer.
49 struct GNUNET_TIME_Relative delay_in;
52 * How long to delay outgoing messages for this peer.
54 struct GNUNET_TIME_Relative delay_out;
57 * Manipulated properties to use for this peer.
59 struct GNUNET_ATS_Properties properties;
62 * Task to schedule delayed sendding
64 struct GNUNET_SCHEDULER_Task *send_delay_task;
69 struct DelayQueueEntry *send_head;
74 struct DelayQueueEntry *send_tail;
79 * Entry in the delay queue for an outbound delayed message
81 struct DelayQueueEntry
86 struct DelayQueueEntry *prev;
91 struct DelayQueueEntry *next;
94 * Peer this entry is belonging to if (NULL == tmp): enqueued in
95 * generic DLL and scheduled by generic_send_delay_task else:
96 * enqueued in tmp->send_head and tmp->send_tail and scheduled by
97 * tmp->send_delay_task
104 struct GNUNET_PeerIdentity id;
107 * Absolute time when to send
109 struct GNUNET_TIME_Absolute sent_at;
124 struct GNUNET_TIME_Relative timeout;
127 * Transports send continuation
129 GST_NeighbourSendContinuation cont;
132 * Transports send continuation cls
138 * Hashmap contain all peers currently manipulated
140 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
143 * Inbound delay to apply to all peers.
145 static struct GNUNET_TIME_Relative delay_in;
148 * Outbound delay to apply to all peers.
150 static struct GNUNET_TIME_Relative delay_out;
153 * DLL head for delayed messages based on general delay
155 static struct DelayQueueEntry *generic_dqe_head;
158 * DLL tail for delayed messages based on general delay
160 static struct DelayQueueEntry *generic_dqe_tail;
163 * Task to schedule delayed sending based on general delay
165 static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
169 * Set traffic metric to manipulate
171 * @param message containing information
174 GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
176 static struct GNUNET_PeerIdentity zero;
179 if (0 == memcmp (&tm->peer,
181 sizeof(struct GNUNET_PeerIdentity)))
183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184 "Received traffic metrics for all peers\n");
185 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
186 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 "Received traffic metrics for peer `%s'\n",
191 GNUNET_i2s (&tm->peer));
193 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
196 tmp = GNUNET_new (struct TM_Peer);
197 tmp->peer = tm->peer;
198 GNUNET_CONTAINER_multipeermap_put (peers,
201 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
203 GNUNET_ATS_properties_ntoh (&tmp->properties,
205 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
206 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
211 * We have delayed transmission, now it is time to send the
214 * @param cls the `struct DelayQueueEntry` to transmit
217 send_delayed (void *cls)
219 struct DelayQueueEntry *dqe = cls;
220 struct DelayQueueEntry *next;
221 struct TM_Peer *tmp = dqe->tmp;
222 struct GNUNET_TIME_Relative delay;
224 GNUNET_break (GNUNET_YES ==
225 GST_neighbours_test_connected (&dqe->id));
228 tmp->send_delay_task = NULL;
229 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
232 next = tmp->send_head;
235 /* More delayed messages */
236 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
237 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
238 &send_delayed, next);
243 /* Remove from generic queue */
244 generic_send_delay_task = NULL;
245 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
248 next = generic_dqe_head;
251 /* More delayed messages */
252 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
253 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
258 GST_neighbours_send (&dqe->id,
269 * Adapter function between transport's send function and transport plugins.
270 * Delays message transmission if an artificial delay is configured.
272 * @param target the peer the message to send to
273 * @param msg the message received
274 * @param msg_size message size
275 * @param timeout timeout
276 * @param cont the continuation to call after sending
277 * @param cont_cls cls for @a cont
280 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
283 struct GNUNET_TIME_Relative timeout,
284 GST_NeighbourSendContinuation cont,
288 struct DelayQueueEntry *dqe;
289 struct GNUNET_TIME_Relative delay;
292 GNUNET_CONTAINER_multipeermap_get (peers,
294 delay = tmp->delay_out;
297 if (0 == delay.rel_value_us)
300 GST_neighbours_send (target,
307 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
310 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
312 dqe->cont_cls = cont_cls;
314 dqe->msg_size = msg_size;
315 dqe->timeout = timeout;
316 GNUNET_memcpy (dqe->msg,
321 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
324 if (NULL == generic_send_delay_task)
325 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
331 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
334 if (NULL == tmp->send_delay_task)
335 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
341 (unsigned int) msg_size,
343 GNUNET_STRINGS_relative_time_to_string (delay,
349 * Function that will be called to manipulate ATS information according to
350 * current manipulation settings
352 * @param address binary address
353 * @param session the session
354 * @param prop[IN|OUT] metrics to modify
357 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
358 struct GNUNET_ATS_Session *session,
359 struct GNUNET_ATS_Properties *prop)
361 const struct GNUNET_PeerIdentity *peer = &address->peer;
364 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
367 *prop = tmp->properties;
372 * Adapter function between transport plugins and transport receive function
373 * manipulation delays for next send.
375 * @param cls the closure for transport
376 * @param address the address and the peer the message was received from
377 * @param message the message received
378 * @param session the session the message was received on
379 * @return manipulated delay for next receive
381 struct GNUNET_TIME_Relative
382 GST_manipulation_recv (void *cls,
383 const struct GNUNET_HELLO_Address *address,
384 struct GNUNET_ATS_Session *session,
385 const struct GNUNET_MessageHeader *message)
388 struct GNUNET_TIME_Relative quota_delay;
389 struct GNUNET_TIME_Relative m_delay;
392 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
394 m_delay = tmp->delay_in;
398 quota_delay = GST_receive_callback (cls,
402 m_delay = GNUNET_TIME_relative_max (m_delay,
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405 "Delaying next receive for peer `%s' for %s\n",
406 GNUNET_i2s (&address->peer),
407 GNUNET_STRINGS_relative_time_to_string (m_delay,
414 * Initialize traffic manipulation
417 GST_manipulation_init ()
419 struct GNUNET_TIME_Relative delay;
422 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
424 "MANIPULATE_DELAY_IN",
426 (delay.rel_value_us > 0) )
428 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
429 "Delaying inbound traffic for %s\n",
430 GNUNET_STRINGS_relative_time_to_string (delay,
435 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
437 "MANIPULATE_DELAY_OUT",
439 (delay.rel_value_us > 0) )
441 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
442 "Delaying outbound traffic for %s\n",
443 GNUNET_STRINGS_relative_time_to_string (delay,
447 peers = GNUNET_CONTAINER_multipeermap_create (4,
453 * Notify manipulation about disconnect so it can discard queued messages
455 * @param peer the disconnecting peer
458 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
461 struct DelayQueueEntry *dqe;
462 struct DelayQueueEntry *next;
464 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
468 while (NULL != (dqe = tmp->send_head))
470 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
473 if (NULL != dqe->cont)
474 dqe->cont (dqe->cont_cls,
481 next = generic_dqe_head;
482 while (NULL != (dqe = next))
485 if (0 == memcmp (peer,
489 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
492 if (NULL != dqe->cont)
493 dqe->cont (dqe->cont_cls,
500 if (NULL != generic_send_delay_task)
502 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
503 generic_send_delay_task = NULL;
504 if (NULL != generic_dqe_head)
505 generic_send_delay_task
506 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(generic_dqe_head->sent_at),
514 * Free manipulation information about a peer.
517 * @param key peer the info is about
518 * @param value a `struct TM_Peer` to free
519 * @return #GNUNET_OK (continue to iterate)
522 free_tmps (void *cls,
523 const struct GNUNET_PeerIdentity *key,
526 struct TM_Peer *tmp = value;
527 struct DelayQueueEntry *dqe;
529 GNUNET_break (GNUNET_YES ==
530 GNUNET_CONTAINER_multipeermap_remove (peers,
533 while (NULL != (dqe = tmp->send_head))
535 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
538 if (NULL != dqe->cont)
539 dqe->cont (dqe->cont_cls,
545 if (NULL != tmp->send_delay_task)
547 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
548 tmp->send_delay_task = NULL;
556 * Stop traffic manipulation
559 GST_manipulation_stop ()
561 struct DelayQueueEntry *cur;
563 GNUNET_CONTAINER_multipeermap_iterate (peers,
566 GNUNET_CONTAINER_multipeermap_destroy (peers);
568 while (NULL != (cur = generic_dqe_head))
570 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
573 if (NULL != cur->cont)
574 cur->cont (cur->cont_cls,
580 if (NULL != generic_send_delay_task)
582 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
583 generic_send_delay_task = NULL;
587 /* end of file gnunet-service-transport_manipulation.c */