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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
17 * @file transport/gnunet-service-transport_manipulation.c
18 * @brief transport component manipulation traffic for simulation
19 * @author Christian Grothoff
20 * @author Matthias Wachs
23 #include "gnunet-service-transport_hello.h"
24 #include "gnunet-service-transport_neighbours.h"
25 #include "gnunet-service-transport_plugins.h"
26 #include "gnunet-service-transport_validation.h"
27 #include "gnunet-service-transport.h"
28 #include "transport.h"
32 * Struct containing information about manipulations to a specific peer
39 struct GNUNET_PeerIdentity peer;
42 * How long to delay incoming messages for this peer.
44 struct GNUNET_TIME_Relative delay_in;
47 * How long to delay outgoing messages for this peer.
49 struct GNUNET_TIME_Relative delay_out;
52 * Manipulated properties to use for this peer.
54 struct GNUNET_ATS_Properties properties;
57 * Task to schedule delayed sendding
59 struct GNUNET_SCHEDULER_Task *send_delay_task;
64 struct DelayQueueEntry *send_head;
69 struct DelayQueueEntry *send_tail;
74 * Entry in the delay queue for an outbound delayed message
76 struct DelayQueueEntry
81 struct DelayQueueEntry *prev;
86 struct DelayQueueEntry *next;
89 * Peer this entry is belonging to if (NULL == tmp): enqueued in
90 * generic DLL and scheduled by generic_send_delay_task else:
91 * enqueued in tmp->send_head and tmp->send_tail and scheduled by
92 * tmp->send_delay_task
99 struct GNUNET_PeerIdentity id;
102 * Absolute time when to send
104 struct GNUNET_TIME_Absolute sent_at;
119 struct GNUNET_TIME_Relative timeout;
122 * Transports send continuation
124 GST_NeighbourSendContinuation cont;
127 * Transports send continuation cls
133 * Hashmap contain all peers currently manipulated
135 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
138 * Inbound delay to apply to all peers.
140 static struct GNUNET_TIME_Relative delay_in;
143 * Outbound delay to apply to all peers.
145 static struct GNUNET_TIME_Relative delay_out;
148 * DLL head for delayed messages based on general delay
150 static struct DelayQueueEntry *generic_dqe_head;
153 * DLL tail for delayed messages based on general delay
155 static struct DelayQueueEntry *generic_dqe_tail;
158 * Task to schedule delayed sending based on general delay
160 static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
164 * Set traffic metric to manipulate
166 * @param message containing information
169 GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
171 static struct GNUNET_PeerIdentity zero;
174 if (0 == memcmp (&tm->peer,
176 sizeof(struct GNUNET_PeerIdentity)))
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179 "Received traffic metrics for all peers\n");
180 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
181 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185 "Received traffic metrics for peer `%s'\n",
186 GNUNET_i2s (&tm->peer));
188 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
191 tmp = GNUNET_new (struct TM_Peer);
192 tmp->peer = tm->peer;
193 GNUNET_CONTAINER_multipeermap_put (peers,
196 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
198 GNUNET_ATS_properties_ntoh (&tmp->properties,
200 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
201 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
206 * We have delayed transmission, now it is time to send the
209 * @param cls the `struct DelayQueueEntry` to transmit
212 send_delayed (void *cls)
214 struct DelayQueueEntry *dqe = cls;
215 struct DelayQueueEntry *next;
216 struct TM_Peer *tmp = dqe->tmp;
218 GNUNET_break (GNUNET_YES ==
219 GST_neighbours_test_connected (&dqe->id));
222 tmp->send_delay_task = NULL;
223 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
226 next = tmp->send_head;
229 /* More delayed messages */
230 tmp->send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
237 /* Remove from generic queue */
238 generic_send_delay_task = NULL;
239 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
242 next = generic_dqe_head;
245 /* More delayed messages */
246 generic_send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
251 GST_neighbours_send (&dqe->id,
262 * Adapter function between transport's send function and transport plugins.
263 * Delays message transmission if an artificial delay is configured.
265 * @param target the peer the message to send to
266 * @param msg the message received
267 * @param msg_size message size
268 * @param timeout timeout
269 * @param cont the continuation to call after sending
270 * @param cont_cls cls for @a cont
273 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
276 struct GNUNET_TIME_Relative timeout,
277 GST_NeighbourSendContinuation cont,
281 struct DelayQueueEntry *dqe;
282 struct GNUNET_TIME_Relative delay;
285 GNUNET_CONTAINER_multipeermap_get (peers,
287 delay = tmp->delay_out;
290 if (0 == delay.rel_value_us)
293 GST_neighbours_send (target,
300 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
303 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
305 dqe->cont_cls = cont_cls;
307 dqe->msg_size = msg_size;
308 dqe->timeout = timeout;
309 GNUNET_memcpy (dqe->msg,
314 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
317 if (NULL == generic_send_delay_task)
318 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
324 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
327 if (NULL == tmp->send_delay_task)
328 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
334 (unsigned int) msg_size,
336 GNUNET_STRINGS_relative_time_to_string (delay,
342 * Function that will be called to manipulate ATS information according to
343 * current manipulation settings
345 * @param address binary address
346 * @param session the session
347 * @param prop[IN|OUT] metrics to modify
350 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
351 struct GNUNET_ATS_Session *session,
352 struct GNUNET_ATS_Properties *prop)
354 const struct GNUNET_PeerIdentity *peer = &address->peer;
357 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
360 *prop = tmp->properties;
365 * Adapter function between transport plugins and transport receive function
366 * manipulation delays for next send.
368 * @param cls the closure for transport
369 * @param address the address and the peer the message was received from
370 * @param message the message received
371 * @param session the session the message was received on
372 * @return manipulated delay for next receive
374 struct GNUNET_TIME_Relative
375 GST_manipulation_recv (void *cls,
376 const struct GNUNET_HELLO_Address *address,
377 struct GNUNET_ATS_Session *session,
378 const struct GNUNET_MessageHeader *message)
381 struct GNUNET_TIME_Relative quota_delay;
382 struct GNUNET_TIME_Relative m_delay;
385 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
387 m_delay = tmp->delay_in;
391 quota_delay = GST_receive_callback (cls,
395 m_delay = GNUNET_TIME_relative_max (m_delay,
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Delaying next receive for peer `%s' for %s\n",
399 GNUNET_i2s (&address->peer),
400 GNUNET_STRINGS_relative_time_to_string (m_delay,
407 * Initialize traffic manipulation
410 GST_manipulation_init ()
412 struct GNUNET_TIME_Relative delay;
415 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
417 "MANIPULATE_DELAY_IN",
419 (delay.rel_value_us > 0) )
421 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
422 "Delaying inbound traffic for %s\n",
423 GNUNET_STRINGS_relative_time_to_string (delay,
428 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
430 "MANIPULATE_DELAY_OUT",
432 (delay.rel_value_us > 0) )
434 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435 "Delaying outbound traffic for %s\n",
436 GNUNET_STRINGS_relative_time_to_string (delay,
440 peers = GNUNET_CONTAINER_multipeermap_create (4,
446 * Notify manipulation about disconnect so it can discard queued messages
448 * @param peer the disconnecting peer
451 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
454 struct DelayQueueEntry *dqe;
455 struct DelayQueueEntry *next;
457 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
461 while (NULL != (dqe = tmp->send_head))
463 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
466 if (NULL != dqe->cont)
467 dqe->cont (dqe->cont_cls,
474 next = generic_dqe_head;
475 while (NULL != (dqe = next))
478 if (0 == memcmp (peer,
482 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
485 if (NULL != dqe->cont)
486 dqe->cont (dqe->cont_cls,
493 if (NULL != generic_send_delay_task)
495 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
496 generic_send_delay_task = NULL;
497 if (NULL != generic_dqe_head)
498 generic_send_delay_task
499 = GNUNET_SCHEDULER_add_at (generic_dqe_head->sent_at,
507 * Free manipulation information about a peer.
510 * @param key peer the info is about
511 * @param value a `struct TM_Peer` to free
512 * @return #GNUNET_OK (continue to iterate)
515 free_tmps (void *cls,
516 const struct GNUNET_PeerIdentity *key,
519 struct TM_Peer *tmp = value;
520 struct DelayQueueEntry *dqe;
522 GNUNET_break (GNUNET_YES ==
523 GNUNET_CONTAINER_multipeermap_remove (peers,
526 while (NULL != (dqe = tmp->send_head))
528 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
531 if (NULL != dqe->cont)
532 dqe->cont (dqe->cont_cls,
538 if (NULL != tmp->send_delay_task)
540 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
541 tmp->send_delay_task = NULL;
549 * Stop traffic manipulation
552 GST_manipulation_stop ()
554 struct DelayQueueEntry *cur;
556 GNUNET_CONTAINER_multipeermap_iterate (peers,
559 GNUNET_CONTAINER_multipeermap_destroy (peers);
561 while (NULL != (cur = generic_dqe_head))
563 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
566 if (NULL != cur->cont)
567 cur->cont (cur->cont_cls,
573 if (NULL != generic_send_delay_task)
575 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
576 generic_send_delay_task = NULL;
580 /* end of file gnunet-service-transport_manipulation.c */