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