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