-fix compiler warning
[oweals/gnunet.git] / src / transport / gnunet-service-transport_manipulation.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013 GNUnet e.V.
4
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.
9
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.
14
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.
19  */
20
21 /**
22  * @file transport/gnunet-service-transport_manipulation.c
23  * @brief transport component manipulation traffic for simulation
24  * @author Christian Grothoff
25  * @author Matthias Wachs
26  */
27 #include "platform.h"
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"
34
35
36 /**
37  * Struct containing information about manipulations to a specific peer
38  */
39 struct TM_Peer
40 {
41   /**
42    * Peer ID
43    */
44   struct GNUNET_PeerIdentity peer;
45
46   /**
47    * How long to delay incoming messages for this peer.
48    */
49   struct GNUNET_TIME_Relative delay_in;
50
51   /**
52    * How long to delay outgoing messages for this peer.
53    */
54   struct GNUNET_TIME_Relative delay_out;
55
56   /**
57    * Manipulated properties to use for this peer.
58    */
59   struct GNUNET_ATS_Properties properties;
60
61   /**
62    * Task to schedule delayed sendding
63    */
64   struct GNUNET_SCHEDULER_Task *send_delay_task;
65
66   /**
67    * Send queue DLL head
68    */
69   struct DelayQueueEntry *send_head;
70
71   /**
72    * Send queue DLL tail
73    */
74   struct DelayQueueEntry *send_tail;
75 };
76
77
78 /**
79  * Entry in the delay queue for an outbound delayed message
80  */
81 struct DelayQueueEntry
82 {
83   /**
84    * Next in DLL
85    */
86   struct DelayQueueEntry *prev;
87
88   /**
89    * Previous in DLL
90    */
91   struct DelayQueueEntry *next;
92
93   /**
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
98    */
99   struct TM_Peer *tmp;
100
101   /**
102    * Peer ID
103    */
104   struct GNUNET_PeerIdentity id;
105
106   /**
107    * Absolute time when to send
108    */
109   struct GNUNET_TIME_Absolute sent_at;
110
111   /**
112    * The message
113    */
114   void *msg;
115
116   /**
117    * The message size
118    */
119   size_t msg_size;
120
121   /**
122    * Message timeout
123    */
124   struct GNUNET_TIME_Relative timeout;
125
126   /**
127    * Transports send continuation
128    */
129   GST_NeighbourSendContinuation cont;
130
131   /**
132    * Transports send continuation cls
133    */
134   void *cont_cls;
135 };
136
137 /**
138  * Hashmap contain all peers currently manipulated
139  */
140 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
141
142 /**
143  * Inbound delay to apply to all peers.
144  */
145 static struct GNUNET_TIME_Relative delay_in;
146
147 /**
148  * Outbound delay to apply to all peers.
149  */
150 static struct GNUNET_TIME_Relative delay_out;
151
152 /**
153  * DLL head for delayed messages based on general delay
154  */
155 static struct DelayQueueEntry *generic_dqe_head;
156
157 /**
158  * DLL tail for delayed messages based on general delay
159  */
160 static struct DelayQueueEntry *generic_dqe_tail;
161
162 /**
163  * Task to schedule delayed sending based on general delay
164  */
165 static struct GNUNET_SCHEDULER_Task *generic_send_delay_task;
166
167
168 /**
169  * Set traffic metric to manipulate
170  *
171  * @param message containing information
172  */
173 void
174 GST_manipulation_set_metric (const struct TrafficMetricMessage *tm)
175 {
176   static struct GNUNET_PeerIdentity zero;
177   struct TM_Peer *tmp;
178
179   if (0 == memcmp (&tm->peer,
180                    &zero,
181                    sizeof(struct GNUNET_PeerIdentity)))
182   {
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);
187     return;
188   }
189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190               "Received traffic metrics for peer `%s'\n",
191               GNUNET_i2s (&tm->peer));
192   if (NULL ==
193       (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
194                                                 &tm->peer)))
195   {
196     tmp = GNUNET_new (struct TM_Peer);
197     tmp->peer = tm->peer;
198     GNUNET_CONTAINER_multipeermap_put (peers,
199                                        &tm->peer,
200                                        tmp,
201                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
202   }
203   GNUNET_ATS_properties_ntoh (&tmp->properties,
204                               &tm->properties);
205   tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in);
206   tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out);
207 }
208
209
210 /**
211  * We have delayed transmission, now it is time to send the
212  * message.
213  *
214  * @param cls the `struct DelayQueueEntry` to transmit
215  */
216 static void
217 send_delayed (void *cls)
218 {
219   struct DelayQueueEntry *dqe = cls;
220   struct DelayQueueEntry *next;
221   struct TM_Peer *tmp = dqe->tmp;
222   struct GNUNET_TIME_Relative delay;
223
224   GNUNET_break (GNUNET_YES ==
225                 GST_neighbours_test_connected (&dqe->id));
226   if (NULL != tmp)
227   {
228     tmp->send_delay_task = NULL;
229     GNUNET_CONTAINER_DLL_remove (tmp->send_head,
230                                  tmp->send_tail,
231                                  dqe);
232     next = tmp->send_head;
233     if (NULL != next)
234     {
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);
239     }
240   }
241   else
242   {
243     /* Remove from generic queue */
244     generic_send_delay_task = NULL;
245     GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
246                                  generic_dqe_tail,
247                                  dqe);
248     next = generic_dqe_head;
249     if (NULL != next)
250     {
251       /* More delayed messages */
252       delay = GNUNET_TIME_absolute_get_remaining(next->sent_at);
253       generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
254                                                               &send_delayed,
255                                                               next);
256     }
257   }
258   GST_neighbours_send (&dqe->id,
259                        dqe->msg,
260                        dqe->msg_size,
261                        dqe->timeout,
262                        dqe->cont,
263                        dqe->cont_cls);
264   GNUNET_free(dqe);
265 }
266
267
268 /**
269  * Adapter function between transport's send function and transport plugins.
270  * Delays message transmission if an artificial delay is configured.
271  *
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
278  */
279 void
280 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
281                        const void *msg,
282                        size_t msg_size,
283                        struct GNUNET_TIME_Relative timeout,
284                        GST_NeighbourSendContinuation cont,
285                        void *cont_cls)
286 {
287   struct TM_Peer *tmp;
288   struct DelayQueueEntry *dqe;
289   struct GNUNET_TIME_Relative delay;
290
291   if (NULL != (tmp =
292                GNUNET_CONTAINER_multipeermap_get (peers,
293                                                   target)))
294     delay = tmp->delay_out;
295   else
296     delay = delay_out;
297   if (0 == delay.rel_value_us)
298   {
299     /* Normal sending */
300     GST_neighbours_send (target,
301                          msg,
302                          msg_size,
303                          timeout,
304                          cont, cont_cls);
305     return;
306   }
307   dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
308   dqe->id = *target;
309   dqe->tmp = tmp;
310   dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
311   dqe->cont = cont;
312   dqe->cont_cls = cont_cls;
313   dqe->msg = &dqe[1];
314   dqe->msg_size = msg_size;
315   dqe->timeout = timeout;
316   GNUNET_memcpy (dqe->msg,
317           msg,
318           msg_size);
319   if (NULL == tmp)
320   {
321     GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
322                                       generic_dqe_tail,
323                                       dqe);
324     if (NULL == generic_send_delay_task)
325       generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
326                                                               &send_delayed,
327                                                               dqe);
328   }
329   else
330   {
331     GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
332                                       tmp->send_tail,
333                                       dqe);
334     if (NULL == tmp->send_delay_task)
335       tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
336                                                            &send_delayed,
337                                                            dqe);
338   }
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,
342               GNUNET_i2s (target),
343               GNUNET_STRINGS_relative_time_to_string (delay,
344                                                       GNUNET_YES));
345 }
346
347
348 /**
349  * Function that will be called to manipulate ATS information according to
350  * current manipulation settings
351  *
352  * @param address binary address
353  * @param session the session
354  * @param prop[IN|OUT] metrics to modify
355  */
356 void
357 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
358                                      struct GNUNET_ATS_Session *session,
359                                      struct GNUNET_ATS_Properties *prop)
360 {
361   const struct GNUNET_PeerIdentity *peer = &address->peer;
362   struct TM_Peer *tmp;
363
364   tmp = GNUNET_CONTAINER_multipeermap_get (peers,
365                                            peer);
366   if (NULL != tmp)
367     *prop = tmp->properties;
368 }
369
370
371 /**
372  * Adapter function between transport plugins and transport receive function
373  * manipulation delays for next send.
374  *
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
380  */
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)
386 {
387   struct TM_Peer *tmp;
388   struct GNUNET_TIME_Relative quota_delay;
389   struct GNUNET_TIME_Relative m_delay;
390
391   if (NULL !=
392       (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
393                                                 &address->peer)))
394     m_delay = tmp->delay_in;
395   else
396     m_delay = delay_in;
397
398   quota_delay = GST_receive_callback (cls,
399                                       address,
400                                       session,
401                                       message);
402   m_delay = GNUNET_TIME_relative_max (m_delay,
403                                       quota_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,
408                                                       GNUNET_YES));
409   return m_delay;
410 }
411
412
413 /**
414  * Initialize traffic manipulation
415  */
416 void
417 GST_manipulation_init ()
418 {
419   struct GNUNET_TIME_Relative delay;
420
421   if ( (GNUNET_OK ==
422         GNUNET_CONFIGURATION_get_value_time (GST_cfg,
423                                              "transport",
424                                              "MANIPULATE_DELAY_IN",
425                                              &delay)) &&
426        (delay.rel_value_us > 0) )
427   {
428     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
429                 "Delaying inbound traffic for %s\n",
430                 GNUNET_STRINGS_relative_time_to_string (delay,
431                                                         GNUNET_YES));
432     delay_in = delay;
433   }
434   if ( (GNUNET_OK ==
435         GNUNET_CONFIGURATION_get_value_time (GST_cfg,
436                                              "transport",
437                                              "MANIPULATE_DELAY_OUT",
438                                              &delay)) &&
439        (delay.rel_value_us > 0) )
440   {
441     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
442                 "Delaying outbound traffic for %s\n",
443                 GNUNET_STRINGS_relative_time_to_string (delay,
444                                                         GNUNET_YES));
445     delay_out = delay;
446   }
447   peers = GNUNET_CONTAINER_multipeermap_create (4,
448                                                 GNUNET_NO);
449 }
450
451
452 /**
453  * Notify manipulation about disconnect so it can discard queued messages
454  *
455  * @param peer the disconnecting peer
456  */
457 void
458 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
459 {
460   struct TM_Peer *tmp;
461   struct DelayQueueEntry *dqe;
462   struct DelayQueueEntry *next;
463
464   tmp = GNUNET_CONTAINER_multipeermap_get (peers,
465                                            peer);
466   if (NULL != tmp)
467   {
468     while (NULL != (dqe = tmp->send_head))
469     {
470       GNUNET_CONTAINER_DLL_remove (tmp->send_head,
471                                    tmp->send_tail,
472                                    dqe);
473       if (NULL != dqe->cont)
474         dqe->cont (dqe->cont_cls,
475                    GNUNET_SYSERR,
476                    dqe->msg_size,
477                    0);
478       GNUNET_free(dqe);
479     }
480   }
481   next = generic_dqe_head;
482   while (NULL != (dqe = next))
483   {
484     next = dqe->next;
485     if (0 == memcmp (peer,
486                      &dqe->id,
487                      sizeof (dqe->id)))
488     {
489       GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
490                                    generic_dqe_tail,
491                                    dqe);
492       if (NULL != dqe->cont)
493         dqe->cont (dqe->cont_cls,
494                    GNUNET_SYSERR,
495                    dqe->msg_size,
496                    0);
497       GNUNET_free(dqe);
498     }
499   }
500   if (NULL != generic_send_delay_task)
501   {
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),
507                                         &send_delayed,
508                                         generic_dqe_head);
509   }
510 }
511
512
513 /**
514  * Free manipulation information about a peer.
515  *
516  * @param cls NULL
517  * @param key peer the info is about
518  * @param value a `struct TM_Peer` to free
519  * @return #GNUNET_OK (continue to iterate)
520  */
521 static int
522 free_tmps (void *cls,
523            const struct GNUNET_PeerIdentity *key,
524            void *value)
525 {
526   struct TM_Peer *tmp = value;
527   struct DelayQueueEntry *dqe;
528
529   GNUNET_break (GNUNET_YES ==
530                 GNUNET_CONTAINER_multipeermap_remove (peers,
531                                                       key,
532                                                       value));
533   while (NULL != (dqe = tmp->send_head))
534   {
535     GNUNET_CONTAINER_DLL_remove (tmp->send_head,
536                                  tmp->send_tail,
537                                  dqe);
538     if (NULL != dqe->cont)
539       dqe->cont (dqe->cont_cls,
540                  GNUNET_SYSERR,
541                  dqe->msg_size,
542                  0);
543     GNUNET_free (dqe);
544   }
545   if (NULL != tmp->send_delay_task)
546   {
547     GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
548     tmp->send_delay_task = NULL;
549   }
550   GNUNET_free (tmp);
551   return GNUNET_OK;
552 }
553
554
555 /**
556  * Stop traffic manipulation
557  */
558 void
559 GST_manipulation_stop ()
560 {
561   struct DelayQueueEntry *cur;
562
563   GNUNET_CONTAINER_multipeermap_iterate (peers,
564                                          &free_tmps,
565                                          NULL);
566   GNUNET_CONTAINER_multipeermap_destroy (peers);
567   peers = NULL;
568   while (NULL != (cur = generic_dqe_head))
569   {
570     GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
571                                  generic_dqe_tail,
572                                  cur);
573     if (NULL != cur->cont)
574       cur->cont (cur->cont_cls,
575                  GNUNET_SYSERR,
576                  cur->msg_size,
577                  0);
578     GNUNET_free (cur);
579   }
580   if (NULL != generic_send_delay_task)
581   {
582     GNUNET_SCHEDULER_cancel (generic_send_delay_task);
583     generic_send_delay_task = NULL;
584   }
585 }
586
587 /* end of file gnunet-service-transport_manipulation.c */