documentation
[oweals/gnunet.git] / src / transport / gnunet-service-transport_manipulation.c
1 /*
2      This file is part of GNUnet.
3      (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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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 #define DELAY 0
38 #define DISTANCE 1
39
40
41 enum TRAFFIC_METRIC_DIRECTION
42 {
43         TM_SEND = 0,
44         TM_RECEIVE = 1,
45         TM_BOTH = 2
46 };
47
48 struct GST_ManipulationHandle man_handle;
49
50
51
52 /**
53  * Struct containing information about manipulations to a specific peer
54  */
55 struct TM_Peer;
56
57 /**
58  * Manipulation entry
59  */
60 struct PropManipulationEntry
61 {
62         /**
63          * Next in DLL
64          */
65         struct PropManipulationEntry *next;
66
67         /**
68          * Previous in DLL
69          */
70         struct PropManipulationEntry *prev;
71
72         /**
73          * ATS type in HBO
74          */
75         uint32_t type;
76
77         /**
78          * Value in HBO
79          */
80         uint32_t metrics[TM_BOTH];
81
82 };
83
84 /**
85  * Struct containing information about manipulations to a specific peer
86  */
87 struct TM_Peer
88 {
89         /**
90          * Peer ID
91          */
92         struct GNUNET_PeerIdentity peer;
93
94         struct PropManipulationEntry *head;
95         struct PropManipulationEntry *tail;
96
97         /**
98          * Peer specific manipulation metrics
99          */
100         uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
101
102         /**
103          * Task to schedule delayed sendding
104          */
105         GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
106
107         /**
108          * Send queue DLL head
109          */
110         struct DelayQueueEntry *send_head;
111
112         /**
113          * Send queue DLL tail
114          */
115         struct DelayQueueEntry *send_tail;
116 };
117
118
119 struct GST_ManipulationHandle
120 {
121         /**
122          * Hashmap contain all peers currently manipulated
123          */
124         struct GNUNET_CONTAINER_MultiHashMap *peers;
125
126         /**
127          * Peer containing information for general manipulation
128          */
129         struct TM_Peer general;
130 };
131
132
133
134 /**
135  * Entry in the delay queue for an outbound delayed message
136  */
137 struct DelayQueueEntry
138 {
139         /**
140          * Next in DLL
141          */
142         struct DelayQueueEntry *prev;
143
144         /**
145          * Previous in DLL
146          */
147         struct DelayQueueEntry *next;
148
149         /**
150          * Peer this entry is belonging to
151          * if (NULL == tmp): enqueued in generic DLL and scheduled by generic_send_delay_task
152          * else: enqueued in tmp->send_head and tmp->send_tail and scheduled by tmp->send_delay_task
153          */
154         struct TM_Peer *tmp;
155
156         /**
157          * Peer ID
158          */
159         struct GNUNET_PeerIdentity id;
160
161         /**
162          * Absolute time when to send
163          */
164         struct GNUNET_TIME_Absolute sent_at;
165
166         /**
167          * The message
168          */
169         void *msg;
170
171         /**
172          * The message size
173          */
174         size_t msg_size;
175
176         /**
177          * Message timeout
178          */
179         struct GNUNET_TIME_Relative timeout;
180
181         /**
182          * Transports send continuation
183          */
184         GST_NeighbourSendContinuation cont;
185
186         /**
187          * Transports send continuation cls
188          */
189         void *cont_cls;
190 };
191
192 /**
193  * DLL head for delayed messages based on general delay
194  */
195 struct DelayQueueEntry *generic_dqe_head;
196
197 /**
198  * DLL tail for delayed messages based on general delay
199  */
200 struct DelayQueueEntry *generic_dqe_tail;
201
202 /**
203  * Task to schedule delayed sending based on general delay
204  */
205 GNUNET_SCHEDULER_TaskIdentifier generic_send_delay_task;
206
207 static void
208 set_metric (struct TM_Peer *dest, int direction, uint32_t type, uint32_t value)
209 {
210         struct PropManipulationEntry *cur;
211         for (cur = dest->head; NULL != cur; cur = cur->next)
212         {
213                 if (cur->type == type)
214                         break;
215         }
216         if (NULL == cur)
217         {
218                 cur = GNUNET_malloc (sizeof (struct PropManipulationEntry));
219                 GNUNET_CONTAINER_DLL_insert (dest->head, dest->tail, cur);
220                 cur->type = type;
221                 cur->metrics[TM_SEND] = UINT32_MAX;
222                 cur->metrics[TM_RECEIVE] = UINT32_MAX;
223         }
224
225
226         switch (direction) {
227                 case TM_BOTH:
228                         cur->metrics[TM_SEND] = value;
229                         cur->metrics[TM_RECEIVE] = value;
230                         break;
231                 case TM_SEND:
232                         cur->metrics[TM_SEND] = value;
233                         break;
234                 case TM_RECEIVE:
235                         cur->metrics[TM_RECEIVE] = value;
236                         break;
237                 default:
238                         break;
239         }
240
241 }
242
243 static uint32_t
244 find_metric (struct TM_Peer *dest, uint32_t type, int direction)
245 {
246         struct PropManipulationEntry *cur;
247
248         for (cur = dest->head; NULL != cur; cur = cur->next)
249         {
250                 if (cur->type == type)
251                         return cur->metrics[direction];
252
253         }
254         return UINT32_MAX;
255 }
256
257 /**
258  * Clean up metrics for a peer
259  */
260
261 static void
262 free_metric (struct TM_Peer *dest)
263 {
264         struct PropManipulationEntry *cur;
265         struct PropManipulationEntry *next;
266
267         for (cur = dest->head; NULL != cur; cur = next)
268         {
269                 next = cur->next;
270                 GNUNET_CONTAINER_DLL_remove (dest->head, dest->tail, cur);
271                 GNUNET_free (cur);
272         }
273 }
274
275
276 /**
277  * Set traffic metric to manipulate
278  *
279  * @param cls closure
280  * @param client client sending message
281  * @param message containing information
282  */
283 void
284 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
285     const struct GNUNET_MessageHeader *message)
286 {
287         struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
288         struct GNUNET_PeerIdentity dummy;
289         struct GNUNET_ATS_Information *ats;
290         struct TM_Peer *tmp;
291         uint32_t type;
292         uint32_t value;
293         uint16_t direction;
294         int c;
295         int c2;
296
297         if (0 == ntohs (tm->ats_count))
298           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
299
300         direction = TM_BOTH;
301         switch (ntohs(tm->direction)) {
302                 case 1:
303                         direction = TM_SEND;
304                         break;
305                 case 2:
306                         direction = TM_RECEIVE;
307                         break;
308                 case 3:
309                         direction = TM_BOTH;
310                         break;
311                 default:
312                         break;
313         }
314
315         memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
316         if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
317         {
318                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
319
320                         ats = (struct GNUNET_ATS_Information *) &tm[1];
321                         for (c = 0; c < ntohs (tm->ats_count); c++)
322                         {
323                                         type = htonl (ats[c].type);
324                                         value = htonl (ats[c].value);
325                                         set_metric (&man_handle.general, direction, type, value);
326                         }
327                         return;
328         }
329
330         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
331                         GNUNET_i2s(&tm->peer));
332
333         if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
334         {
335                         tmp = GNUNET_malloc (sizeof (struct TM_Peer));
336                         tmp->peer = (tm->peer);
337                         for (c = 0; c < TM_BOTH; c++)
338                         {
339                                         for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
340                                         {
341                                                         tmp->metrics[c][c2] = UINT32_MAX;
342                                         }
343                         }
344                         GNUNET_CONTAINER_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
345         }
346
347         ats = (struct GNUNET_ATS_Information *) &tm[1];
348         for (c = 0; c < ntohs (tm->ats_count); c++)
349         {
350                         type = htonl (ats[c].type);
351                         value = htonl (ats[c].value);
352                         set_metric (tmp, direction, type, value);
353         }
354
355   GNUNET_SERVER_receive_done (client, GNUNET_OK);
356 }
357
358 static void
359 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
360 {
361         struct DelayQueueEntry *dqe = cls;
362         struct DelayQueueEntry *next;
363         struct TM_Peer *tmp = dqe->tmp;
364         struct GNUNET_TIME_Relative delay;
365
366         if (NULL != tmp)
367         {
368                         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
369                         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
370                         GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
371
372                         next = tmp->send_head;
373                         if (NULL != next)
374                         {
375                                 /* More delayed messages */
376                                 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
377                                 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
378                         }
379         }
380         else
381         {
382                 /* Remove from generic queue */
383                         generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
384                         GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, dqe);
385                         GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
386                         next = generic_dqe_head;
387                         if (NULL != next)
388                         {
389                                 /* More delayed messages */
390                                 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
391                                 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
392                         }
393         }
394
395         GNUNET_free (dqe);
396 }
397
398
399 /**
400  * Adapter function between transport's send function and transport plugins
401  *
402  * @param target the peer the message to send to
403  * @param msg the message received
404  * @param msg_size message size
405  * @param timeout timeout
406  * @param cont the continuation to call after sending
407  * @param cont_cls cls for continuation
408  */
409 void
410 GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg,
411     size_t msg_size, struct GNUNET_TIME_Relative timeout,
412     GST_NeighbourSendContinuation cont, void *cont_cls)
413 {
414         struct TM_Peer *tmp;
415         struct DelayQueueEntry *dqe;
416         struct GNUNET_TIME_Relative delay;
417
418         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
419         {
420                         /* Manipulate here */
421                         /* Delay */
422                         if (UINT32_MAX != find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
423                         {
424                                         /* We have a delay */
425                                         delay.rel_value = find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
426                                         dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
427                                         dqe->id = *target;
428                                         dqe->tmp = tmp;
429                                         dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
430                                         dqe->cont = cont;
431                                         dqe->cont_cls = cont_cls;
432                                         dqe->msg = &dqe[1];
433                                         dqe->msg_size = msg_size;
434                                         dqe->timeout = timeout;
435                                         memcpy (dqe->msg, msg, msg_size);
436                                         GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
437                                         if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
438                                                 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
439                                         return;
440                         }
441         }
442         else if (UINT32_MAX != find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
443         {
444                         /* We have a delay */
445                         delay.rel_value = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
446                         dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
447                         dqe->id = *target;
448                         dqe->tmp = NULL;
449                         dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
450                         dqe->cont = cont;
451                         dqe->cont_cls = cont_cls;
452                         dqe->msg = &dqe[1];
453                         dqe->msg_size = msg_size;
454                         dqe->timeout = timeout;
455                         memcpy (dqe->msg, msg, msg_size);
456                         GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head, generic_dqe_tail, dqe);
457                         if (GNUNET_SCHEDULER_NO_TASK == generic_send_delay_task)
458                                 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
459                         return;
460         }
461
462         /* Normal sending */
463         GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
464 }
465
466
467 /**
468  * Function that will be called to manipulate ATS information according to
469  * current manipulation settings
470  *
471  * @param peer the peer
472  * @param address binary address
473  * @param session the session
474  * @param ats the ats information
475  * @param ats_count the number of ats information
476  */
477 struct GNUNET_ATS_Information *
478 GST_manipulation_manipulate_metrics (const struct GNUNET_PeerIdentity *peer,
479                 const struct GNUNET_HELLO_Address *address,
480                 struct Session *session,
481                 const struct GNUNET_ATS_Information *ats,
482                 uint32_t ats_count)
483 {
484         struct GNUNET_ATS_Information *ats_new = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *ats_count);
485         struct TM_Peer *tmp;
486         uint32_t m_tmp;
487         uint32_t g_tmp;
488         int d;
489         tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey);
490
491         for (d = 0; d < ats_count; d++)
492         {
493                 ats_new[d] = ats[d];
494                 m_tmp = UINT32_MAX;
495                 g_tmp = UINT32_MAX;
496                 if (NULL != tmp)
497                         m_tmp = find_metric (tmp, ntohl(ats[d].type), TM_RECEIVE);
498                 g_tmp = find_metric (&man_handle.general, ntohl(ats[d].type), TM_RECEIVE);
499
500                 if (UINT32_MAX != g_tmp)
501                                 ats_new[d].value = htonl(g_tmp);
502                 if (UINT32_MAX != m_tmp)
503                                 ats_new[d].value = htonl(m_tmp);
504         }
505
506         return ats_new;
507 }
508
509
510 /**
511  * Adapter function between transport plugins and transport receive function
512  * manipulation delays for next send.
513  *
514  * @param cls the closure for transport
515  * @param peer the peer the message was received from
516  * @param message the message received
517  * @param session the session the message was received on
518  * @param sender_address the sender address
519  * @param sender_address_len the length of the sender address
520  * @return manipulated delay for next receive
521  */
522 struct GNUNET_TIME_Relative
523 GST_manipulation_recv (void *cls,
524                 const struct GNUNET_PeerIdentity *peer,
525     const struct GNUNET_MessageHeader *message,
526     struct Session *session,
527     const char *sender_address,
528     uint16_t sender_address_len)
529 {
530         struct TM_Peer *tmp;
531         uint32_t p_recv_delay;
532         uint32_t g_recv_delay;
533         struct GNUNET_TIME_Relative quota_delay;
534         struct GNUNET_TIME_Relative m_delay;
535
536         g_recv_delay = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
537         if ((g_recv_delay >= GNUNET_TIME_UNIT_ZERO.rel_value) && (UINT32_MAX != g_recv_delay))
538                 m_delay.rel_value = g_recv_delay; /* Global delay */
539         else
540                 m_delay = GNUNET_TIME_UNIT_ZERO;
541
542         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
543         {
544                         /* Manipulate receive delay */
545                         p_recv_delay = find_metric (tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
546                         if (UINT32_MAX != p_recv_delay)
547                                         m_delay.rel_value = p_recv_delay; /* Peer specific delay */
548         }
549
550         quota_delay = GST_receive_callback (cls, peer, message,
551                         session, sender_address, sender_address_len);
552         if (quota_delay.rel_value > m_delay.rel_value)
553                 return quota_delay;
554         else
555                 return m_delay;
556 }
557
558
559 /**
560  * Initialize traffic manipulation
561  *
562  * @param GST_cfg configuration handle
563  */
564 void
565 GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
566 {
567         unsigned long long tmp;
568
569         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
570                         "transport", "MANIPULATE_DISTANCE_IN", &tmp))
571         {
572                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting inbound distance_in to %u\n",
573                                 (unsigned long long) tmp);
574                 set_metric (&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
575         }
576
577         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
578                         "transport", "MANIPULATE_DISTANCE_OUT", &tmp))
579         {
580                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting outbound distance_in to %u\n",
581                                 (unsigned long long) tmp);
582                 set_metric (&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
583         }
584
585         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
586                         "transport", "MANIPULATE_DELAY_IN", &tmp))
587         {
588                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying inbound traffic for %llu ms\n",
589                                 (unsigned long long) tmp);
590                 set_metric (&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DELAY, tmp);
591         }
592
593
594         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
595                         "transport", "MANIPULATE_DELAY_OUT", &tmp))
596         {
597                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying outbound traffic for %llu ms\n",
598                                 (unsigned long long) tmp);
599                 set_metric (&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DELAY, tmp);
600         }
601
602         man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
603 }
604
605
606 static int 
607 free_tmps (void *cls,
608            const struct GNUNET_HashCode * key,
609            void *value)
610 {
611         struct DelayQueueEntry *dqe;
612         struct DelayQueueEntry *next;
613         if (NULL != value)
614         {
615                         struct TM_Peer *tmp = (struct TM_Peer *) value;
616                         GNUNET_CONTAINER_multihashmap_remove (man_handle.peers, key, value);
617                         free_metric (tmp);
618                         next = tmp->send_head;
619                         while (NULL != (dqe = next))
620                         {
621                                         next = dqe->next;
622                                         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
623                                         GNUNET_free (dqe);
624                         }
625                         if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
626                         {
627                                         GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
628                                         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
629                         }
630                         GNUNET_free (tmp);
631         }
632         return GNUNET_OK;
633 }
634
635
636 /**
637  * Stop traffic manipulation
638  */
639 void
640 GST_manipulation_stop ()
641 {
642         struct DelayQueueEntry *cur;
643         struct DelayQueueEntry *next;
644         GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
645         GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
646
647         next = generic_dqe_head;
648         while (NULL != (cur = next))
649         {
650                         next = cur->next;
651                         GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, cur);
652                         GNUNET_free (cur);
653         }
654         if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
655         {
656                         GNUNET_SCHEDULER_cancel (generic_send_delay_task);
657                         generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
658         }
659
660         free_metric (&man_handle.general);
661         man_handle.peers = NULL;
662 }
663
664
665 /* end of file gnunet-service-transport_manipulation.c */