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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file transport/gnunet-service-transport_manipulation.c
21 * @brief transport component manipulation traffic for simulation
22 * @author Christian Grothoff
23 * @author Matthias Wachs
26 #include "gnunet-service-transport_hello.h"
27 #include "gnunet-service-transport_neighbours.h"
28 #include "gnunet-service-transport_plugins.h"
29 #include "gnunet-service-transport_validation.h"
30 #include "gnunet-service-transport.h"
31 #include "transport.h"
35 * Struct containing information about manipulations to a specific peer
42 struct GNUNET_PeerIdentity peer;
45 * How long to delay incoming messages for this peer.
47 struct GNUNET_TIME_Relative delay_in;
50 * How long to delay outgoing messages for this peer.
52 struct GNUNET_TIME_Relative delay_out;
55 * Manipulated properties to use for this peer.
57 struct GNUNET_ATS_Properties properties;
60 * Task to schedule delayed sendding
62 struct GNUNET_SCHEDULER_Task *send_delay_task;
67 struct DelayQueueEntry *send_head;
72 struct DelayQueueEntry *send_tail;
77 * Entry in the delay queue for an outbound delayed message
79 struct DelayQueueEntry
84 struct DelayQueueEntry *prev;
89 struct DelayQueueEntry *next;
92 * Peer this entry is belonging to if (NULL == tmp): enqueued in
93 * generic DLL and scheduled by generic_send_delay_task else:
94 * enqueued in tmp->send_head and tmp->send_tail and scheduled by
95 * tmp->send_delay_task
102 struct GNUNET_PeerIdentity id;
105 * Absolute time when to send
107 struct GNUNET_TIME_Absolute sent_at;
122 struct GNUNET_TIME_Relative timeout;
125 * Transports send continuation
127 GST_NeighbourSendContinuation cont;
130 * Transports send continuation cls
136 * Hashmap contain all peers currently manipulated
138 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
141 * Inbound delay to apply to all peers.
143 static struct GNUNET_TIME_Relative delay_in;
146 * Outbound delay to apply to all peers.
148 static struct GNUNET_TIME_Relative delay_out;
151 * DLL head for delayed messages based on general delay
153 static struct DelayQueueEntry *generic_dqe_head;
156 * DLL tail for delayed messages based on general delay
158 static struct DelayQueueEntry *generic_dqe_tail;
161 * Task to schedule delayed sending based on general delay
163 static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
167 * Set traffic metric to manipulate
169 * @param message containing information
172 GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
174 static struct GNUNET_PeerIdentity zero;
177 if (0 == memcmp (&tm->peer,
179 sizeof(struct GNUNET_PeerIdentity)))
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182 "Received traffic metrics for all peers\n");
183 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
184 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
188 "Received traffic metrics for peer `%s'\n",
189 GNUNET_i2s (&tm->peer));
191 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
194 tmp = GNUNET_new (struct TM_Peer);
195 tmp->peer = tm->peer;
196 GNUNET_CONTAINER_multipeermap_put (peers,
199 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
201 GNUNET_ATS_properties_ntoh (&tmp->properties,
203 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
204 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
209 * We have delayed transmission, now it is time to send the
212 * @param cls the `struct DelayQueueEntry` to transmit
215 send_delayed (void *cls)
217 struct DelayQueueEntry *dqe = cls;
218 struct DelayQueueEntry *next;
219 struct TM_Peer *tmp = dqe->tmp;
221 GNUNET_break (GNUNET_YES ==
222 GST_neighbours_test_connected (&dqe->id));
225 tmp->send_delay_task = NULL;
226 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
229 next = tmp->send_head;
232 /* More delayed messages */
233 tmp->send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
240 /* Remove from generic queue */
241 generic_send_delay_task = NULL;
242 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
245 next = generic_dqe_head;
248 /* More delayed messages */
249 generic_send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
254 GST_neighbours_send (&dqe->id,
265 * Adapter function between transport's send function and transport plugins.
266 * Delays message transmission if an artificial delay is configured.
268 * @param target the peer the message to send to
269 * @param msg the message received
270 * @param msg_size message size
271 * @param timeout timeout
272 * @param cont the continuation to call after sending
273 * @param cont_cls cls for @a cont
276 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
279 struct GNUNET_TIME_Relative timeout,
280 GST_NeighbourSendContinuation cont,
284 struct DelayQueueEntry *dqe;
285 struct GNUNET_TIME_Relative delay;
288 GNUNET_CONTAINER_multipeermap_get (peers,
290 delay = tmp->delay_out;
293 if (0 == delay.rel_value_us)
296 GST_neighbours_send (target,
303 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
306 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
308 dqe->cont_cls = cont_cls;
310 dqe->msg_size = msg_size;
311 dqe->timeout = timeout;
312 GNUNET_memcpy (dqe->msg,
317 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
320 if (NULL == generic_send_delay_task)
321 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
327 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
330 if (NULL == tmp->send_delay_task)
331 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
337 (unsigned int) msg_size,
339 GNUNET_STRINGS_relative_time_to_string (delay,
345 * Function that will be called to manipulate ATS information according to
346 * current manipulation settings
348 * @param address binary address
349 * @param session the session
350 * @param prop[IN|OUT] metrics to modify
353 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
354 struct GNUNET_ATS_Session *session,
355 struct GNUNET_ATS_Properties *prop)
357 const struct GNUNET_PeerIdentity *peer = &address->peer;
360 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
363 *prop = tmp->properties;
368 * Adapter function between transport plugins and transport receive function
369 * manipulation delays for next send.
371 * @param cls the closure for transport
372 * @param address the address and the peer the message was received from
373 * @param message the message received
374 * @param session the session the message was received on
375 * @return manipulated delay for next receive
377 struct GNUNET_TIME_Relative
378 GST_manipulation_recv (void *cls,
379 const struct GNUNET_HELLO_Address *address,
380 struct GNUNET_ATS_Session *session,
381 const struct GNUNET_MessageHeader *message)
384 struct GNUNET_TIME_Relative quota_delay;
385 struct GNUNET_TIME_Relative m_delay;
388 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
390 m_delay = tmp->delay_in;
394 quota_delay = GST_receive_callback (cls,
398 m_delay = GNUNET_TIME_relative_max (m_delay,
400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
401 "Delaying next receive for peer `%s' for %s\n",
402 GNUNET_i2s (&address->peer),
403 GNUNET_STRINGS_relative_time_to_string (m_delay,
410 * Initialize traffic manipulation
413 GST_manipulation_init ()
415 struct GNUNET_TIME_Relative delay;
418 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
420 "MANIPULATE_DELAY_IN",
422 (delay.rel_value_us > 0) )
424 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
425 "Delaying inbound traffic for %s\n",
426 GNUNET_STRINGS_relative_time_to_string (delay,
431 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
433 "MANIPULATE_DELAY_OUT",
435 (delay.rel_value_us > 0) )
437 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
438 "Delaying outbound traffic for %s\n",
439 GNUNET_STRINGS_relative_time_to_string (delay,
443 peers = GNUNET_CONTAINER_multipeermap_create (4,
449 * Notify manipulation about disconnect so it can discard queued messages
451 * @param peer the disconnecting peer
454 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
457 struct DelayQueueEntry *dqe;
458 struct DelayQueueEntry *next;
460 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
464 while (NULL != (dqe = tmp->send_head))
466 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
469 if (NULL != dqe->cont)
470 dqe->cont (dqe->cont_cls,
477 next = generic_dqe_head;
478 while (NULL != (dqe = next))
481 if (0 == memcmp (peer,
485 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
488 if (NULL != dqe->cont)
489 dqe->cont (dqe->cont_cls,
496 if (NULL != generic_send_delay_task)
498 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
499 generic_send_delay_task = NULL;
500 if (NULL != generic_dqe_head)
501 generic_send_delay_task
502 = GNUNET_SCHEDULER_add_at (generic_dqe_head->sent_at,
510 * Free manipulation information about a peer.
513 * @param key peer the info is about
514 * @param value a `struct TM_Peer` to free
515 * @return #GNUNET_OK (continue to iterate)
518 free_tmps (void *cls,
519 const struct GNUNET_PeerIdentity *key,
522 struct TM_Peer *tmp = value;
523 struct DelayQueueEntry *dqe;
525 GNUNET_break (GNUNET_YES ==
526 GNUNET_CONTAINER_multipeermap_remove (peers,
529 while (NULL != (dqe = tmp->send_head))
531 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
534 if (NULL != dqe->cont)
535 dqe->cont (dqe->cont_cls,
541 if (NULL != tmp->send_delay_task)
543 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
544 tmp->send_delay_task = NULL;
552 * Stop traffic manipulation
555 GST_manipulation_stop ()
557 struct DelayQueueEntry *cur;
559 GNUNET_CONTAINER_multipeermap_iterate (peers,
562 GNUNET_CONTAINER_multipeermap_destroy (peers);
564 while (NULL != (cur = generic_dqe_head))
566 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
569 if (NULL != cur->cont)
570 cur->cont (cur->cont_cls,
576 if (NULL != generic_send_delay_task)
578 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
579 generic_send_delay_task = NULL;
583 /* end of file gnunet-service-transport_manipulation.c */