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