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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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;
223 GNUNET_break (GNUNET_YES ==
224 GST_neighbours_test_connected (&dqe->id));
227 tmp->send_delay_task = NULL;
228 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
231 next = tmp->send_head;
234 /* More delayed messages */
235 tmp->send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
242 /* Remove from generic queue */
243 generic_send_delay_task = NULL;
244 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
247 next = generic_dqe_head;
250 /* More delayed messages */
251 generic_send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
256 GST_neighbours_send (&dqe->id,
267 * Adapter function between transport's send function and transport plugins.
268 * Delays message transmission if an artificial delay is configured.
270 * @param target the peer the message to send to
271 * @param msg the message received
272 * @param msg_size message size
273 * @param timeout timeout
274 * @param cont the continuation to call after sending
275 * @param cont_cls cls for @a cont
278 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
281 struct GNUNET_TIME_Relative timeout,
282 GST_NeighbourSendContinuation cont,
286 struct DelayQueueEntry *dqe;
287 struct GNUNET_TIME_Relative delay;
290 GNUNET_CONTAINER_multipeermap_get (peers,
292 delay = tmp->delay_out;
295 if (0 == delay.rel_value_us)
298 GST_neighbours_send (target,
305 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
308 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
310 dqe->cont_cls = cont_cls;
312 dqe->msg_size = msg_size;
313 dqe->timeout = timeout;
314 GNUNET_memcpy (dqe->msg,
319 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
322 if (NULL == generic_send_delay_task)
323 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
329 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
332 if (NULL == tmp->send_delay_task)
333 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
339 (unsigned int) msg_size,
341 GNUNET_STRINGS_relative_time_to_string (delay,
347 * Function that will be called to manipulate ATS information according to
348 * current manipulation settings
350 * @param address binary address
351 * @param session the session
352 * @param prop[IN|OUT] metrics to modify
355 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
356 struct GNUNET_ATS_Session *session,
357 struct GNUNET_ATS_Properties *prop)
359 const struct GNUNET_PeerIdentity *peer = &address->peer;
362 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
365 *prop = tmp->properties;
370 * Adapter function between transport plugins and transport receive function
371 * manipulation delays for next send.
373 * @param cls the closure for transport
374 * @param address the address and the peer the message was received from
375 * @param message the message received
376 * @param session the session the message was received on
377 * @return manipulated delay for next receive
379 struct GNUNET_TIME_Relative
380 GST_manipulation_recv (void *cls,
381 const struct GNUNET_HELLO_Address *address,
382 struct GNUNET_ATS_Session *session,
383 const struct GNUNET_MessageHeader *message)
386 struct GNUNET_TIME_Relative quota_delay;
387 struct GNUNET_TIME_Relative m_delay;
390 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
392 m_delay = tmp->delay_in;
396 quota_delay = GST_receive_callback (cls,
400 m_delay = GNUNET_TIME_relative_max (m_delay,
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403 "Delaying next receive for peer `%s' for %s\n",
404 GNUNET_i2s (&address->peer),
405 GNUNET_STRINGS_relative_time_to_string (m_delay,
412 * Initialize traffic manipulation
415 GST_manipulation_init ()
417 struct GNUNET_TIME_Relative delay;
420 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
422 "MANIPULATE_DELAY_IN",
424 (delay.rel_value_us > 0) )
426 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
427 "Delaying inbound traffic for %s\n",
428 GNUNET_STRINGS_relative_time_to_string (delay,
433 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
435 "MANIPULATE_DELAY_OUT",
437 (delay.rel_value_us > 0) )
439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440 "Delaying outbound traffic for %s\n",
441 GNUNET_STRINGS_relative_time_to_string (delay,
445 peers = GNUNET_CONTAINER_multipeermap_create (4,
451 * Notify manipulation about disconnect so it can discard queued messages
453 * @param peer the disconnecting peer
456 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
459 struct DelayQueueEntry *dqe;
460 struct DelayQueueEntry *next;
462 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
466 while (NULL != (dqe = tmp->send_head))
468 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
471 if (NULL != dqe->cont)
472 dqe->cont (dqe->cont_cls,
479 next = generic_dqe_head;
480 while (NULL != (dqe = next))
483 if (0 == memcmp (peer,
487 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
490 if (NULL != dqe->cont)
491 dqe->cont (dqe->cont_cls,
498 if (NULL != generic_send_delay_task)
500 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
501 generic_send_delay_task = NULL;
502 if (NULL != generic_dqe_head)
503 generic_send_delay_task
504 = GNUNET_SCHEDULER_add_at (generic_dqe_head->sent_at,
512 * Free manipulation information about a peer.
515 * @param key peer the info is about
516 * @param value a `struct TM_Peer` to free
517 * @return #GNUNET_OK (continue to iterate)
520 free_tmps (void *cls,
521 const struct GNUNET_PeerIdentity *key,
524 struct TM_Peer *tmp = value;
525 struct DelayQueueEntry *dqe;
527 GNUNET_break (GNUNET_YES ==
528 GNUNET_CONTAINER_multipeermap_remove (peers,
531 while (NULL != (dqe = tmp->send_head))
533 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
536 if (NULL != dqe->cont)
537 dqe->cont (dqe->cont_cls,
543 if (NULL != tmp->send_delay_task)
545 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
546 tmp->send_delay_task = NULL;
554 * Stop traffic manipulation
557 GST_manipulation_stop ()
559 struct DelayQueueEntry *cur;
561 GNUNET_CONTAINER_multipeermap_iterate (peers,
564 GNUNET_CONTAINER_multipeermap_destroy (peers);
566 while (NULL != (cur = generic_dqe_head))
568 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
571 if (NULL != cur->cont)
572 cur->cont (cur->cont_cls,
578 if (NULL != generic_send_delay_task)
580 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
581 generic_send_delay_task = NULL;
585 /* end of file gnunet-service-transport_manipulation.c */