Merge branch 'master' of git+ssh://gnunet.org/gnunet
[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      SPDX-License-Identifier: AGPL3.0-or-later
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
223   GNUNET_break (GNUNET_YES ==
224                 GST_neighbours_test_connected (&dqe->id));
225   if (NULL != tmp)
226   {
227     tmp->send_delay_task = NULL;
228     GNUNET_CONTAINER_DLL_remove (tmp->send_head,
229                                  tmp->send_tail,
230                                  dqe);
231     next = tmp->send_head;
232     if (NULL != next)
233     {
234       /* More delayed messages */
235       tmp->send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
236                                                       &send_delayed,
237                                                       next);
238     }
239   }
240   else
241   {
242     /* Remove from generic queue */
243     generic_send_delay_task = NULL;
244     GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
245                                  generic_dqe_tail,
246                                  dqe);
247     next = generic_dqe_head;
248     if (NULL != next)
249     {
250       /* More delayed messages */
251       generic_send_delay_task = GNUNET_SCHEDULER_add_at (next->sent_at,
252                                                          &send_delayed,
253                                                          next);
254     }
255   }
256   GST_neighbours_send (&dqe->id,
257                        dqe->msg,
258                        dqe->msg_size,
259                        dqe->timeout,
260                        dqe->cont,
261                        dqe->cont_cls);
262   GNUNET_free (dqe);
263 }
264
265
266 /**
267  * Adapter function between transport's send function and transport plugins.
268  * Delays message transmission if an artificial delay is configured.
269  *
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
276  */
277 void
278 GST_manipulation_send (const struct GNUNET_PeerIdentity *target,
279                        const void *msg,
280                        size_t msg_size,
281                        struct GNUNET_TIME_Relative timeout,
282                        GST_NeighbourSendContinuation cont,
283                        void *cont_cls)
284 {
285   struct TM_Peer *tmp;
286   struct DelayQueueEntry *dqe;
287   struct GNUNET_TIME_Relative delay;
288
289   if (NULL != (tmp =
290                  GNUNET_CONTAINER_multipeermap_get (peers,
291                                                     target)))
292     delay = tmp->delay_out;
293   else
294     delay = delay_out;
295   if (0 == delay.rel_value_us)
296   {
297     /* Normal sending */
298     GST_neighbours_send (target,
299                          msg,
300                          msg_size,
301                          timeout,
302                          cont, cont_cls);
303     return;
304   }
305   dqe = GNUNET_malloc (sizeof(struct DelayQueueEntry) + msg_size);
306   dqe->id = *target;
307   dqe->tmp = tmp;
308   dqe->sent_at = GNUNET_TIME_relative_to_absolute (delay);
309   dqe->cont = cont;
310   dqe->cont_cls = cont_cls;
311   dqe->msg = &dqe[1];
312   dqe->msg_size = msg_size;
313   dqe->timeout = timeout;
314   GNUNET_memcpy (dqe->msg,
315                  msg,
316                  msg_size);
317   if (NULL == tmp)
318   {
319     GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head,
320                                       generic_dqe_tail,
321                                       dqe);
322     if (NULL == generic_send_delay_task)
323       generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
324                                                               &send_delayed,
325                                                               dqe);
326   }
327   else
328   {
329     GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head,
330                                       tmp->send_tail,
331                                       dqe);
332     if (NULL == tmp->send_delay_task)
333       tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay,
334                                                            &send_delayed,
335                                                            dqe);
336   }
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,
340               GNUNET_i2s (target),
341               GNUNET_STRINGS_relative_time_to_string (delay,
342                                                       GNUNET_YES));
343 }
344
345
346 /**
347  * Function that will be called to manipulate ATS information according to
348  * current manipulation settings
349  *
350  * @param address binary address
351  * @param session the session
352  * @param prop[IN|OUT] metrics to modify
353  */
354 void
355 GST_manipulation_manipulate_metrics (const struct GNUNET_HELLO_Address *address,
356                                      struct GNUNET_ATS_Session *session,
357                                      struct GNUNET_ATS_Properties *prop)
358 {
359   const struct GNUNET_PeerIdentity *peer = &address->peer;
360   struct TM_Peer *tmp;
361
362   tmp = GNUNET_CONTAINER_multipeermap_get (peers,
363                                            peer);
364   if (NULL != tmp)
365     *prop = tmp->properties;
366 }
367
368
369 /**
370  * Adapter function between transport plugins and transport receive function
371  * manipulation delays for next send.
372  *
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
378  */
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)
384 {
385   struct TM_Peer *tmp;
386   struct GNUNET_TIME_Relative quota_delay;
387   struct GNUNET_TIME_Relative m_delay;
388
389   if (NULL !=
390       (tmp = GNUNET_CONTAINER_multipeermap_get (peers,
391                                                 &address->peer)))
392     m_delay = tmp->delay_in;
393   else
394     m_delay = delay_in;
395
396   quota_delay = GST_receive_callback (cls,
397                                       address,
398                                       session,
399                                       message);
400   m_delay = GNUNET_TIME_relative_max (m_delay,
401                                       quota_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,
406                                                       GNUNET_YES));
407   return m_delay;
408 }
409
410
411 /**
412  * Initialize traffic manipulation
413  */
414 void
415 GST_manipulation_init ()
416 {
417   struct GNUNET_TIME_Relative delay;
418
419   if ((GNUNET_OK ==
420        GNUNET_CONFIGURATION_get_value_time (GST_cfg,
421                                             "transport",
422                                             "MANIPULATE_DELAY_IN",
423                                             &delay)) &&
424       (delay.rel_value_us > 0))
425   {
426     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
427                 "Delaying inbound traffic for %s\n",
428                 GNUNET_STRINGS_relative_time_to_string (delay,
429                                                         GNUNET_YES));
430     delay_in = delay;
431   }
432   if ((GNUNET_OK ==
433        GNUNET_CONFIGURATION_get_value_time (GST_cfg,
434                                             "transport",
435                                             "MANIPULATE_DELAY_OUT",
436                                             &delay)) &&
437       (delay.rel_value_us > 0))
438   {
439     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440                 "Delaying outbound traffic for %s\n",
441                 GNUNET_STRINGS_relative_time_to_string (delay,
442                                                         GNUNET_YES));
443     delay_out = delay;
444   }
445   peers = GNUNET_CONTAINER_multipeermap_create (4,
446                                                 GNUNET_NO);
447 }
448
449
450 /**
451  * Notify manipulation about disconnect so it can discard queued messages
452  *
453  * @param peer the disconnecting peer
454  */
455 void
456 GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer)
457 {
458   struct TM_Peer *tmp;
459   struct DelayQueueEntry *dqe;
460   struct DelayQueueEntry *next;
461
462   tmp = GNUNET_CONTAINER_multipeermap_get (peers,
463                                            peer);
464   if (NULL != tmp)
465   {
466     while (NULL != (dqe = tmp->send_head))
467     {
468       GNUNET_CONTAINER_DLL_remove (tmp->send_head,
469                                    tmp->send_tail,
470                                    dqe);
471       if (NULL != dqe->cont)
472         dqe->cont (dqe->cont_cls,
473                    GNUNET_SYSERR,
474                    dqe->msg_size,
475                    0);
476       GNUNET_free (dqe);
477     }
478   }
479   next = generic_dqe_head;
480   while (NULL != (dqe = next))
481   {
482     next = dqe->next;
483     if (0 == memcmp (peer,
484                      &dqe->id,
485                      sizeof(dqe->id)))
486     {
487       GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
488                                    generic_dqe_tail,
489                                    dqe);
490       if (NULL != dqe->cont)
491         dqe->cont (dqe->cont_cls,
492                    GNUNET_SYSERR,
493                    dqe->msg_size,
494                    0);
495       GNUNET_free (dqe);
496     }
497   }
498   if (NULL != generic_send_delay_task)
499   {
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,
505                                    &send_delayed,
506                                    generic_dqe_head);
507   }
508 }
509
510
511 /**
512  * Free manipulation information about a peer.
513  *
514  * @param cls NULL
515  * @param key peer the info is about
516  * @param value a `struct TM_Peer` to free
517  * @return #GNUNET_OK (continue to iterate)
518  */
519 static int
520 free_tmps (void *cls,
521            const struct GNUNET_PeerIdentity *key,
522            void *value)
523 {
524   struct TM_Peer *tmp = value;
525   struct DelayQueueEntry *dqe;
526
527   GNUNET_break (GNUNET_YES ==
528                 GNUNET_CONTAINER_multipeermap_remove (peers,
529                                                       key,
530                                                       value));
531   while (NULL != (dqe = tmp->send_head))
532   {
533     GNUNET_CONTAINER_DLL_remove (tmp->send_head,
534                                  tmp->send_tail,
535                                  dqe);
536     if (NULL != dqe->cont)
537       dqe->cont (dqe->cont_cls,
538                  GNUNET_SYSERR,
539                  dqe->msg_size,
540                  0);
541     GNUNET_free (dqe);
542   }
543   if (NULL != tmp->send_delay_task)
544   {
545     GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
546     tmp->send_delay_task = NULL;
547   }
548   GNUNET_free (tmp);
549   return GNUNET_OK;
550 }
551
552
553 /**
554  * Stop traffic manipulation
555  */
556 void
557 GST_manipulation_stop ()
558 {
559   struct DelayQueueEntry *cur;
560
561   GNUNET_CONTAINER_multipeermap_iterate (peers,
562                                          &free_tmps,
563                                          NULL);
564   GNUNET_CONTAINER_multipeermap_destroy (peers);
565   peers = NULL;
566   while (NULL != (cur = generic_dqe_head))
567   {
568     GNUNET_CONTAINER_DLL_remove (generic_dqe_head,
569                                  generic_dqe_tail,
570                                  cur);
571     if (NULL != cur->cont)
572       cur->cont (cur->cont_cls,
573                  GNUNET_SYSERR,
574                  cur->msg_size,
575                  0);
576     GNUNET_free (cur);
577   }
578   if (NULL != generic_send_delay_task)
579   {
580     GNUNET_SCHEDULER_cancel (generic_send_delay_task);
581     generic_send_delay_task = NULL;
582   }
583 }
584
585
586 /* end of file gnunet-service-transport_manipulation.c */