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