- fix
[oweals/gnunet.git] / src / transport / gnunet-service-transport_manipulation.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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 struct GST_ManipulationHandle
52 {
53         struct GNUNET_CONTAINER_MultiHashMap *peers;
54
55         /**
56          * General inbound delay
57          */
58         struct GNUNET_TIME_Relative delay_recv;
59
60         /**
61          * General outbound delay
62          */
63         struct GNUNET_TIME_Relative delay_send;
64
65         /**
66          * General inbound distance
67          */
68          unsigned long long  distance_recv;
69
70         /**
71          * General outbound distance
72          */
73          unsigned long long distance_send;
74
75 };
76
77
78 struct TM_Peer;
79
80
81
82 struct DelayQueueEntry
83 {
84         struct DelayQueueEntry *prev;
85         struct DelayQueueEntry *next;
86         struct TM_Peer *tmp;
87         struct GNUNET_TIME_Absolute sent_at;
88         void *msg;
89         size_t msg_size;
90         struct GNUNET_TIME_Relative timeout;
91         GST_NeighbourSendContinuation cont;
92         void *cont_cls;
93 };
94
95 struct TM_Peer
96 {
97         struct GNUNET_PeerIdentity peer;
98         uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
99         GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
100         struct DelayQueueEntry *send_head;
101         struct DelayQueueEntry *send_tail;
102 };
103
104
105
106 static void
107 set_delay(struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
108 {
109         uint32_t val;
110         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n",
111                         "DELAY", GNUNET_i2s(peer),
112                         (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value);
113
114         if (UINT32_MAX == value)
115                 val = UINT32_MAX - 1; /* prevent overflow */
116         else if (0 == value)
117                 val = UINT32_MAX; /* disable */
118         else
119                 val = value;
120
121         switch (direction) {
122                 case TM_BOTH:
123                         tmp->metrics[TM_SEND][DELAY] = val;
124                         tmp->metrics[TM_RECEIVE][DELAY] = val;
125                         break;
126                 case TM_SEND:
127                         tmp->metrics[TM_SEND][DELAY] = val;
128                         break;
129                 case TM_RECEIVE:
130                         tmp->metrics[TM_RECEIVE][DELAY] = val;
131                         break;
132                 default:
133                         break;
134         }
135
136 }
137
138 static void
139 set_distance (struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
140 {
141         uint32_t val;
142         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n",
143                         "DISTANCE", GNUNET_i2s(peer),
144                         (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value);
145
146         if (UINT32_MAX == value)
147                 val = UINT32_MAX - 1; /* prevent overflow */
148         else if (0 == value)
149                 val = UINT32_MAX; /* disable */
150         else
151                 val = value;
152
153         switch (direction) {
154         case TM_BOTH:
155                 tmp->metrics[TM_SEND][DISTANCE] = val;
156                 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
157                 break;
158         case TM_SEND:
159                 tmp->metrics[TM_SEND][DISTANCE] = val;
160                 break;
161         case TM_RECEIVE:
162                 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
163                 break;
164         default:
165                 break;
166         }
167 }
168
169 void
170 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
171     const struct GNUNET_MessageHeader *message)
172 {
173         struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
174         struct GNUNET_PeerIdentity dummy;
175         struct GNUNET_ATS_Information *ats;
176         struct TM_Peer *tmp;
177         uint32_t type;
178         uint32_t value;
179         uint16_t direction;
180         int c;
181         int c2;
182
183         if (0 == ntohs (tm->ats_count))
184           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
185
186         switch (ntohs(tm->direction)) {
187                 case 1:
188                         direction = TM_SEND;
189                         break;
190                 case 2:
191                         direction = TM_RECEIVE;
192                         break;
193                 case 3:
194                         direction = TM_BOTH;
195                         break;
196                 default:
197                         break;
198         }
199
200         memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
201         if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
202         {
203                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
204
205                         ats = (struct GNUNET_ATS_Information *) &tm[1];
206                         for (c = 0; c < ntohs (tm->ats_count); c++)
207                         {
208                                         type = htonl (ats[c].type);
209                                         value = htonl (ats[c].value);
210
211                                         switch (type) {
212                                                 case GNUNET_ATS_QUALITY_NET_DELAY:
213                                                         if ((TM_RECEIVE == direction) || (TM_BOTH == direction))
214                                                                         man_handle.delay_recv.rel_value = value;
215                                                         if ((TM_SEND == direction) || (TM_BOTH == direction))
216                                                                         man_handle.delay_send.rel_value = value;
217                                                         break;
218                                                 case GNUNET_ATS_QUALITY_NET_DISTANCE:
219                                                         if ((TM_RECEIVE == direction) || (TM_BOTH == direction))
220                                                                         man_handle.distance_recv = value;
221                                                         if ((TM_SEND == direction) || (TM_BOTH == direction))
222                                                                         man_handle.distance_send = value;
223                                                         break;
224                                                 default:
225                                                         break;
226                                         }
227
228                         }
229                         return;
230         }
231
232         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
233                         GNUNET_i2s(&tm->peer));
234
235         if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
236         {
237                         tmp = GNUNET_malloc (sizeof (struct TM_Peer));
238                         tmp->peer = (tm->peer);
239                         for (c = 0; c < TM_BOTH; c++)
240                         {
241                                         for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
242                                         {
243                                                         tmp->metrics[c][c2] = UINT32_MAX;
244                                         }
245                         }
246                         GNUNET_CONTAINER_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
247         }
248
249         ats = (struct GNUNET_ATS_Information *) &tm[1];
250         for (c = 0; c < ntohs (tm->ats_count); c++)
251         {
252                         type = htonl (ats[c].type);
253                         value = htonl (ats[c].value);
254                         switch (type) {
255                                 case GNUNET_ATS_QUALITY_NET_DELAY:
256                                         set_delay (tmp, &tm->peer, direction, value);
257                                         break;
258                                 case GNUNET_ATS_QUALITY_NET_DISTANCE:
259                                         set_distance (tmp, &tm->peer, direction, value);
260                                         break;
261                                 default:
262                                         break;
263                         }
264         }
265
266   GNUNET_SERVER_receive_done (client, GNUNET_OK);
267 }
268
269 static void
270 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
271 {
272         struct DelayQueueEntry *dqe = cls;
273         struct DelayQueueEntry *next;
274         struct TM_Peer *tmp = dqe->tmp;
275         struct GNUNET_TIME_Relative delay;
276         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
277         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
278         GST_neighbours_send (&tmp->peer, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
279
280         next = tmp->send_head;
281         if (NULL != next)
282         {
283                         /* More delayed messages */
284                         delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
285                         tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
286         }
287
288         GNUNET_free (dqe);
289 }
290
291 void
292 GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg,
293     size_t msg_size, struct GNUNET_TIME_Relative timeout,
294     GST_NeighbourSendContinuation cont, void *cont_cls)
295 {
296         struct TM_Peer *tmp;
297         struct DelayQueueEntry *dqe;
298         struct GNUNET_TIME_Relative delay;
299
300         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
301         {
302                         /* Manipulate here */
303                         /* Delay */
304                         if (UINT32_MAX != tmp->metrics[TM_SEND][DELAY])
305                         {
306                                         /* We have a delay */
307                                         delay.rel_value = tmp->metrics[TM_SEND][DELAY];
308                                         dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
309                                         dqe->tmp = tmp;
310                                         dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
311                                         dqe->cont = cont;
312                                         dqe->cont_cls = cont_cls;
313                                         dqe->msg = &dqe[1];
314                                         dqe->msg_size = msg_size;
315                                         dqe->timeout = timeout;
316                                         memcpy (dqe->msg, msg, msg_size);
317                                         GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
318                                         if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
319                                                 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
320                                         return;
321                         }
322         }
323         else if (man_handle.delay_send.rel_value != 0)
324         {
325                         /* We have a delay */
326                         delay = man_handle.delay_send;
327                         dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
328                         dqe->tmp = tmp;
329                         dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
330                         dqe->cont = cont;
331                         dqe->cont_cls = cont_cls;
332                         dqe->msg = &dqe[1];
333                         dqe->msg_size = msg_size;
334                         dqe->timeout = timeout;
335                         memcpy (dqe->msg, msg, msg_size);
336                         GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
337                         if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
338                                 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
339                         return;
340         }
341
342         /* Normal sending */
343         GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
344 }
345
346 struct GNUNET_TIME_Relative
347 GST_manipulation_recv (void *cls,
348                 const struct GNUNET_PeerIdentity *peer,
349     const struct GNUNET_MessageHeader *message,
350     struct Session *session,
351     const char *sender_address,
352     uint16_t sender_address_len)
353 {
354         struct TM_Peer *tmp;
355         //int d;
356         //struct GNUNET_ATS_Information ats_new[ats_count];
357         struct GNUNET_TIME_Relative quota_delay;
358         struct GNUNET_TIME_Relative m_delay;
359
360         if (man_handle.delay_recv.rel_value > GNUNET_TIME_UNIT_ZERO.rel_value)
361                 m_delay = man_handle.delay_recv; /* Global delay */
362         else
363                 m_delay = GNUNET_TIME_UNIT_ZERO;
364
365 #if 0
366         for (d = 0; d < ats_count; d++)
367         {
368                 ats_new[d] = ats[d];
369                 if ((ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) &&
370                                 (man_handle.distance_recv > 0))
371                         ats_new[d].value = htonl(man_handle.distance_recv); /* Global inbound distance */
372         }
373 #endif
374
375         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
376         {
377 #if 0
378                         /* Manipulate distance */
379                         for (d = 0; d < ats_count; d++)
380                         {
381                                         ats_new[d] = ats[d];
382                                         /* Set distance */
383                                         if ((ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) &&
384                                                  (UINT32_MAX != tmp->metrics[TM_RECEIVE][DISTANCE]))
385                                                         ats_new[d].value = htonl(tmp->metrics[TM_RECEIVE][DISTANCE]);
386                         }
387 #endif
388                         /* Manipulate receive delay */
389                         if (UINT32_MAX != tmp->metrics[TM_RECEIVE][DELAY])
390                                         m_delay.rel_value = tmp->metrics[TM_RECEIVE][DELAY]; /* Peer specific delay */
391         }
392
393         quota_delay = GST_receive_callback (cls, peer, message,
394                         session, sender_address, sender_address_len);
395         if (quota_delay.rel_value > m_delay.rel_value)
396                 return quota_delay;
397         else
398                 return m_delay;
399
400 }
401
402 void
403 GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
404 {
405
406         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
407                         "transport", "MANIPULATE_DISTANCE_IN", &man_handle.distance_recv))
408                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting inbound distance_in to %u\n",
409                                 (unsigned long long) man_handle.distance_recv);
410         else
411                 man_handle.distance_recv = 0;
412
413         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
414                         "transport", "MANIPULATE_DISTANCE_OUT", &man_handle.distance_send))
415                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting outbound distance_in to %u\n",
416                                 (unsigned long long) man_handle.distance_send);
417         else
418                 man_handle.distance_send = 0;
419
420         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
421                         "transport", "MANIPULATE_DELAY_IN", &man_handle.delay_recv))
422                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying inbound traffic for %llu ms\n",
423                                 (unsigned long long) man_handle.delay_recv.rel_value);
424         else
425                 man_handle.delay_recv.rel_value = 0;
426
427         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (GST_cfg,
428                         "transport", "MANIPULATE_DELAY_OUT", &man_handle.delay_send))
429                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying outbound traffic for %llu ms\n",
430                         (unsigned long long) man_handle.delay_send.rel_value);
431         else
432                 man_handle.delay_send.rel_value = 0;
433
434         man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
435 }
436
437 int free_tmps (void *cls,
438                                                          const struct GNUNET_HashCode * key,
439                                                          void *value)
440 {
441         struct DelayQueueEntry *dqe;
442         struct DelayQueueEntry *next;
443         if (NULL != value)
444         {
445                         struct TM_Peer *tmp = (struct TM_Peer *) value;
446                         GNUNET_CONTAINER_multihashmap_remove (man_handle.peers, key, value);
447                         next = tmp->send_head;
448                         while (NULL != (dqe = next))
449                         {
450                                         next = dqe->next;
451                                         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
452                                         GNUNET_free (dqe);
453                         }
454                         if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
455                         {
456                                         GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
457                                         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
458                         }
459                         GNUNET_free (tmp);
460         }
461         return GNUNET_OK;
462 }
463
464 void
465 GST_manipulation_stop ()
466 {
467         GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
468
469         GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
470         man_handle.peers = NULL;
471 }
472
473
474 /* end of file gnunet-service-transport_manipulation.c */