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