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