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