2 This file is part of GNUnet.
3 (C) 2010,2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file transport/gnunet-service-transport_manipulation.c
23 * @brief transport component manipulation traffic for simulation
24 * @author Christian Grothoff
25 * @author Matthias Wachs
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"
41 enum TRAFFIC_METRIC_DIRECTION
48 struct GST_ManipulationHandle man_handle;
51 struct GST_ManipulationHandle
53 struct GNUNET_CONTAINER_MultiHashMap *peers;
55 GNUNET_TRANSPORT_UpdateAddressMetrics metric_update_cb;
58 * General inbound delay
60 struct GNUNET_TIME_Relative delay_recv;
63 * General outbound delay
65 struct GNUNET_TIME_Relative delay_send;
68 * General inbound distance
70 unsigned long long distance_recv;
73 * General outbound distance
75 unsigned long long distance_send;
84 struct DelayQueueEntry
86 struct DelayQueueEntry *prev;
87 struct DelayQueueEntry *next;
89 struct GNUNET_TIME_Absolute sent_at;
92 struct GNUNET_TIME_Relative timeout;
93 GST_NeighbourSendContinuation cont;
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;
109 set_delay(struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
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);
116 if (UINT32_MAX == value)
117 val = UINT32_MAX - 1; /* prevent overflow */
119 val = UINT32_MAX; /* disable */
125 tmp->metrics[TM_SEND][DELAY] = val;
126 tmp->metrics[TM_RECEIVE][DELAY] = val;
129 tmp->metrics[TM_SEND][DELAY] = val;
132 tmp->metrics[TM_RECEIVE][DELAY] = val;
141 set_distance (struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
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);
148 if (UINT32_MAX == value)
149 val = UINT32_MAX - 1; /* prevent overflow */
151 val = UINT32_MAX; /* disable */
157 tmp->metrics[TM_SEND][DISTANCE] = val;
158 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
161 tmp->metrics[TM_SEND][DISTANCE] = val;
164 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
172 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
173 const struct GNUNET_MessageHeader *message)
175 struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
176 struct GNUNET_PeerIdentity dummy;
177 struct GNUNET_ATS_Information *ats;
185 if (0 == ntohs (tm->ats_count))
186 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
188 switch (ntohs(tm->direction)) {
193 direction = TM_RECEIVE;
202 memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
203 if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
207 ats = (struct GNUNET_ATS_Information *) &tm[1];
208 for (c = 0; c < ntohs (tm->ats_count); c++)
210 type = htonl (ats[c].type);
211 value = htonl (ats[c].value);
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;
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;
234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
235 GNUNET_i2s(&tm->peer));
237 if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
239 tmp = GNUNET_malloc (sizeof (struct TM_Peer));
240 tmp->peer = (tm->peer);
241 for (c = 0; c < TM_BOTH; c++)
243 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
245 tmp->metrics[c][c2] = UINT32_MAX;
248 GNUNET_CONTAINER_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
251 ats = (struct GNUNET_ATS_Information *) &tm[1];
252 for (c = 0; c < ntohs (tm->ats_count); c++)
254 type = htonl (ats[c].type);
255 value = htonl (ats[c].value);
257 case GNUNET_ATS_QUALITY_NET_DELAY:
258 set_delay (tmp, &tm->peer, direction, value);
260 case GNUNET_ATS_QUALITY_NET_DISTANCE:
261 set_distance (tmp, &tm->peer, direction, value);
268 GNUNET_SERVER_receive_done (client, GNUNET_OK);
272 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
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);
282 next = tmp->send_head;
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);
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)
299 struct DelayQueueEntry *dqe;
300 struct GNUNET_TIME_Relative delay;
302 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
304 /* Manipulate here */
306 if (UINT32_MAX != tmp->metrics[TM_SEND][DELAY])
308 /* We have a delay */
309 delay.rel_value = tmp->metrics[TM_SEND][DELAY];
310 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
312 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
314 dqe->cont_cls = cont_cls;
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);
325 else if (man_handle.delay_send.rel_value != 0)
327 /* We have a delay */
328 delay = man_handle.delay_send;
329 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
331 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
333 dqe->cont_cls = cont_cls;
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);
345 GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
350 * Function that will be called to figure if an address is an loopback,
351 * LAN, WAN etc. address
354 * @param addr binary address
355 * @param addrlen length of the address
356 * @return ATS Information containing the network type
359 GST_manipulation_metrics_recv (void *cls,
360 const struct GNUNET_PeerIdentity *peer,
362 uint16_t address_len,
363 struct Session *session,
364 struct GNUNET_ATS_Information *ats,
368 struct GNUNET_ATS_Information ats_new[ats_count];
375 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
377 if (UINT32_MAX != tmp->metrics[TM_RECEIVE][DISTANCE])
378 m_distance = tmp->metrics[TM_RECEIVE][DISTANCE];
381 for (d = 0; d < ats_count; d++)
384 if (ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE)
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);
393 man_handle.metric_update_cb (cls, peer, address, address_len, session, ats_new, ats_count);
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)
406 struct GNUNET_TIME_Relative quota_delay;
407 struct GNUNET_TIME_Relative m_delay;
409 if (man_handle.delay_recv.rel_value > GNUNET_TIME_UNIT_ZERO.rel_value)
410 m_delay = man_handle.delay_recv; /* Global delay */
412 m_delay = GNUNET_TIME_UNIT_ZERO;
414 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
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 */
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)
431 GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg,
432 GNUNET_TRANSPORT_UpdateAddressMetrics metric_update_cb)
434 man_handle.metric_update_cb = metric_update_cb;
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);
441 man_handle.distance_recv = 0;
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);
448 man_handle.distance_send = 0;
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);
455 man_handle.delay_recv.rel_value = 0;
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);
462 man_handle.delay_send.rel_value = 0;
464 man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
467 int free_tmps (void *cls,
468 const struct GNUNET_HashCode * key,
471 struct DelayQueueEntry *dqe;
472 struct DelayQueueEntry *next;
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))
481 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
484 if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
486 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
487 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
495 GST_manipulation_stop ()
497 GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
499 GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
500 man_handle.peers = NULL;
504 /* end of file gnunet-service-transport_manipulation.c */