2 This file is part of GNUnet.
3 Copyright (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"
39 * Struct containing information about manipulations to a specific peer
46 struct GNUNET_PeerIdentity peer;
49 * How long to delay incoming messages for this peer.
51 struct GNUNET_TIME_Relative delay_in;
54 * How long to delay outgoing messages for this peer.
56 struct GNUNET_TIME_Relative delay_out;
59 * Manipulated properties to use for this peer.
61 struct GNUNET_ATS_Properties properties;
64 * Task to schedule delayed sendding
66 struct GNUNET_SCHEDULER_Task *send_delay_task;
71 struct DelayQueueEntry *send_head;
76 struct DelayQueueEntry *send_tail;
81 * Entry in the delay queue for an outbound delayed message
83 struct DelayQueueEntry
88 struct DelayQueueEntry *prev;
93 struct DelayQueueEntry *next;
96 * Peer this entry is belonging to if (NULL == tmp): enqueued in
97 * generic DLL and scheduled by generic_send_delay_task else:
98 * enqueued in tmp->send_head and tmp->send_tail and scheduled by
99 * tmp->send_delay_task
106 struct GNUNET_PeerIdentity id;
109 * Absolute time when to send
111 struct GNUNET_TIME_Absolute sent_at;
126 struct GNUNET_TIME_Relative timeout;
129 * Transports send continuation
131 GST_NeighbourSendContinuation cont;
134 * Transports send continuation cls
140 * Hashmap contain all peers currently manipulated
142 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
145 * Inbound delay to apply to all peers.
147 static struct GNUNET_TIME_Relative delay_in;
150 * Outbound delay to apply to all peers.
152 static struct GNUNET_TIME_Relative delay_out;
155 * DLL head for delayed messages based on general delay
157 static struct DelayQueueEntry *generic_dqe_head;
160 * DLL tail for delayed messages based on general delay
162 static struct DelayQueueEntry *generic_dqe_tail;
165 * Task to schedule delayed sending based on general delay
167 static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
171 * Set traffic metric to manipulate
174 * @param client client sending message
175 * @param message containing information
178 GST_manipulation_set_metric (void *cls,
179 struct GNUNET_SERVER_Client *client,
180 const struct GNUNET_MessageHeader *message)
182 const struct TrafficMetricMessage *tm;
183 static struct GNUNET_PeerIdentity zero;
186 tm = (const struct TrafficMetricMessage *) message;
187 if (0 == memcmp (&tm->peer,
189 sizeof(struct GNUNET_PeerIdentity)))
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Received traffic metrics for all peers\n");
193 delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
194 delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
195 GNUNET_SERVER_receive_done (client,
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Received traffic metrics for peer `%s'\n",
201 GNUNET_i2s(&tm->peer));
203 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
206 tmp = GNUNET_new (struct TM_Peer);
207 tmp->peer = tm->peer;
208 GNUNET_CONTAINER_multipeermap_put (peers,
211 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
213 GNUNET_ATS_properties_ntoh (&tmp->properties,
215 tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
216 tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
217 GNUNET_SERVER_receive_done (client,
223 * We have delayed transmission, now it is time to send the
226 * @param cls the `struct DelayQueueEntry` to transmit
230 send_delayed (void *cls,
231 const struct GNUNET_SCHEDULER_TaskContext *tc)
233 struct DelayQueueEntry *dqe = cls;
234 struct DelayQueueEntry *next;
235 struct TM_Peer *tmp = dqe->tmp;
236 struct GNUNET_TIME_Relative delay;
238 GNUNET_break (GNUNET_YES ==
239 GST_neighbours_test_connected (&dqe->id));
242 tmp->send_delay_task = NULL;
243 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
246 next = tmp->send_head;
249 /* More delayed messages */
250 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
251 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed(delay,
252 &send_delayed, next);
257 /* Remove from generic queue */
258 generic_send_delay_task = NULL;
259 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
262 next = generic_dqe_head;
265 /* More delayed messages */
266 delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
267 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
272 GST_neighbours_send (&dqe->id,
283 * Adapter function between transport's send function and transport plugins.
284 * Delays message transmission if an artificial delay is configured.
286 * @param target the peer the message to send to
287 * @param msg the message received
288 * @param msg_size message size
289 * @param timeout timeout
290 * @param cont the continuation to call after sending
291 * @param cont_cls cls for @a cont
294 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
297 struct GNUNET_TIME_Relative timeout,
298 GST_NeighbourSendContinuation cont,
302 struct DelayQueueEntry *dqe;
303 struct GNUNET_TIME_Relative delay;
306 GNUNET_CONTAINER_multipeermap_get (peers,
308 delay = tmp->delay_out;
311 if (0 == delay.rel_value_us)
314 GST_neighbours_send (target,
321 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
324 dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
326 dqe->cont_cls = cont_cls;
328 dqe->msg_size = msg_size;
329 dqe->timeout = timeout;
335 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
338 if (NULL == generic_send_delay_task)
339 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
345 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
348 if (NULL == tmp->send_delay_task)
349 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Delaying %u byte message to peer `%s' with peer specific delay for %s\n",
357 GNUNET_STRINGS_relative_time_to_string (delay,
363 * Function that will be called to manipulate ATS information according to
364 * current manipulation settings
366 * @param address binary address
367 * @param session the session
368 * @param prop[IN|OUT] metrics to modify
371 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
372 struct Session *session,
373 struct GNUNET_ATS_Properties *prop)
375 const struct GNUNET_PeerIdentity *peer = &address->peer;
378 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
381 *prop = tmp->properties;
386 * Adapter function between transport plugins and transport receive function
387 * manipulation delays for next send.
389 * @param cls the closure for transport
390 * @param address the address and the peer the message was received from
391 * @param message the message received
392 * @param session the session the message was received on
393 * @return manipulated delay for next receive
395 struct GNUNET_TIME_Relative
396 GST_manipulation_recv (void *cls,
397 const struct GNUNET_HELLO_Address *address,
398 struct Session *session,
399 const struct GNUNET_MessageHeader *message)
402 struct GNUNET_TIME_Relative quota_delay;
403 struct GNUNET_TIME_Relative m_delay;
406 (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
408 m_delay = tmp->delay_in;
412 quota_delay = GST_receive_callback (cls,
416 m_delay = GNUNET_TIME_relative_max (m_delay,
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "Delaying next receive for peer `%s' for %s\n",
420 GNUNET_i2s (&address->peer),
421 GNUNET_STRINGS_relative_time_to_string (m_delay,
428 * Initialize traffic manipulation
431 GST_manipulation_init ()
433 struct GNUNET_TIME_Relative delay;
436 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
438 "MANIPULATE_DELAY_IN",
440 (delay.rel_value_us > 0) )
442 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
443 "Delaying inbound traffic for %s\n",
444 GNUNET_STRINGS_relative_time_to_string (delay,
449 GNUNET_CONFIGURATION_get_value_time (GST_cfg,
451 "MANIPULATE_DELAY_OUT",
453 (delay.rel_value_us > 0) )
455 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
456 "Delaying outbound traffic for %s\n",
457 GNUNET_STRINGS_relative_time_to_string (delay,
461 peers = GNUNET_CONTAINER_multipeermap_create (4,
467 * Notify manipulation about disconnect so it can discard queued messages
469 * @param peer the disconnecting peer
472 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
475 struct DelayQueueEntry *dqe;
476 struct DelayQueueEntry *next;
478 tmp = GNUNET_CONTAINER_multipeermap_get (peers,
482 while (NULL != (dqe = tmp->send_head))
484 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
487 if (NULL != dqe->cont)
488 dqe->cont (dqe->cont_cls,
495 next = generic_dqe_head;
496 while (NULL != (dqe = next))
499 if (0 == memcmp(peer, &dqe->id, sizeof(dqe->id)))
501 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
504 if (NULL != dqe->cont)
505 dqe->cont (dqe->cont_cls,
512 if (NULL != generic_send_delay_task)
514 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
515 generic_send_delay_task = NULL;
516 if (NULL != generic_dqe_head)
517 generic_send_delay_task
518 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(generic_dqe_head->sent_at),
526 * Free manipulation information about a peer.
529 * @param key peer the info is about
530 * @param value a `struct TM_Peer` to free
531 * @return #GNUNET_OK (continue to iterate)
534 free_tmps (void *cls,
535 const struct GNUNET_PeerIdentity *key,
538 struct TM_Peer *tmp = value;
539 struct DelayQueueEntry *dqe;
541 GNUNET_break (GNUNET_YES ==
542 GNUNET_CONTAINER_multipeermap_remove (peers,
545 while (NULL != (dqe = tmp->send_head))
547 GNUNET_CONTAINER_DLL_remove (tmp->send_head,
550 if (NULL != dqe->cont)
551 dqe->cont (dqe->cont_cls,
557 if (NULL != tmp->send_delay_task)
559 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
560 tmp->send_delay_task = NULL;
568 * Stop traffic manipulation
571 GST_manipulation_stop ()
573 struct DelayQueueEntry *cur;
575 GNUNET_CONTAINER_multipeermap_iterate (peers,
578 GNUNET_CONTAINER_multipeermap_destroy (peers);
580 while (NULL != (cur = generic_dqe_head))
582 GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
585 if (NULL != cur->cont)
586 cur->cont (cur->cont_cls,
592 if (NULL != generic_send_delay_task)
594 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
595 generic_send_delay_task = NULL;
599 /* end of file gnunet-service-transport_manipulation.c */