2 This file is part of GNUnet.
3 (C) 2010-2013 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;
53 * Struct containing information about manipulations to a specific peer
60 struct PropManipulationEntry
65 struct PropManipulationEntry *next;
70 struct PropManipulationEntry *prev;
80 uint32_t metrics[TM_BOTH];
85 * Struct containing information about manipulations to a specific peer
92 struct GNUNET_PeerIdentity peer;
94 struct PropManipulationEntry *head;
95 struct PropManipulationEntry *tail;
98 * Peer specific manipulation metrics
100 uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
103 * Task to schedule delayed sendding
105 GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
108 * Send queue DLL head
110 struct DelayQueueEntry *send_head;
113 * Send queue DLL tail
115 struct DelayQueueEntry *send_tail;
119 struct GST_ManipulationHandle
122 * Hashmap contain all peers currently manipulated
124 struct GNUNET_CONTAINER_MultiHashMap *peers;
127 * Peer containing information for general manipulation
129 struct TM_Peer general;
135 * Entry in the delay queue for an outbound delayed message
137 struct DelayQueueEntry
142 struct DelayQueueEntry *prev;
147 struct DelayQueueEntry *next;
150 * Peer this entry is belonging to
151 * if (NULL == tmp): enqueued in generic DLL and scheduled by generic_send_delay_task
152 * else: enqueued in tmp->send_head and tmp->send_tail and scheduled by tmp->send_delay_task
159 struct GNUNET_PeerIdentity id;
162 * Absolute time when to send
164 struct GNUNET_TIME_Absolute sent_at;
179 struct GNUNET_TIME_Relative timeout;
182 * Transports send continuation
184 GST_NeighbourSendContinuation cont;
187 * Transports send continuation cls
193 * DLL head for delayed messages based on general delay
195 struct DelayQueueEntry *generic_dqe_head;
198 * DLL tail for delayed messages based on general delay
200 struct DelayQueueEntry *generic_dqe_tail;
203 * Task to schedule delayed sending based on general delay
205 GNUNET_SCHEDULER_TaskIdentifier generic_send_delay_task;
208 set_metric (struct TM_Peer *dest, int direction, uint32_t type, uint32_t value)
210 struct PropManipulationEntry *cur;
211 for (cur = dest->head; NULL != cur; cur = cur->next)
213 if (cur->type == type)
218 cur = GNUNET_malloc (sizeof (struct PropManipulationEntry));
219 GNUNET_CONTAINER_DLL_insert (dest->head, dest->tail, cur);
221 cur->metrics[TM_SEND] = UINT32_MAX;
222 cur->metrics[TM_RECEIVE] = UINT32_MAX;
228 cur->metrics[TM_SEND] = value;
229 cur->metrics[TM_RECEIVE] = value;
232 cur->metrics[TM_SEND] = value;
235 cur->metrics[TM_RECEIVE] = value;
244 find_metric (struct TM_Peer *dest, uint32_t type, int direction)
246 struct PropManipulationEntry *cur;
248 for (cur = dest->head; NULL != cur; cur = cur->next)
250 if (cur->type == type)
251 return cur->metrics[direction];
258 * Clean up metrics for a peer
262 free_metric (struct TM_Peer *dest)
264 struct PropManipulationEntry *cur;
265 struct PropManipulationEntry *next;
267 for (cur = dest->head; NULL != cur; cur = next)
270 GNUNET_CONTAINER_DLL_remove (dest->head, dest->tail, cur);
277 * Set traffic metric to manipulate
280 * @param client client sending message
281 * @param message containing information
284 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
285 const struct GNUNET_MessageHeader *message)
287 struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
288 struct GNUNET_PeerIdentity dummy;
289 struct GNUNET_ATS_Information *ats;
297 if (0 == ntohs (tm->ats_count))
298 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
301 switch (ntohs(tm->direction)) {
306 direction = TM_RECEIVE;
315 memset (&dummy, '\0', sizeof (struct GNUNET_PeerIdentity));
316 if (0 == memcmp (&tm->peer, &dummy, sizeof (struct GNUNET_PeerIdentity)))
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for all peers \n");
320 ats = (struct GNUNET_ATS_Information *) &tm[1];
321 for (c = 0; c < ntohs (tm->ats_count); c++)
323 type = htonl (ats[c].type);
324 value = htonl (ats[c].value);
325 set_metric (&man_handle.general, direction, type, value);
330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
331 GNUNET_i2s(&tm->peer));
333 if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &tm->peer.hashPubKey)))
335 tmp = GNUNET_malloc (sizeof (struct TM_Peer));
336 tmp->peer = (tm->peer);
337 for (c = 0; c < TM_BOTH; c++)
339 for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
341 tmp->metrics[c][c2] = UINT32_MAX;
344 GNUNET_CONTAINER_multihashmap_put (man_handle.peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
347 ats = (struct GNUNET_ATS_Information *) &tm[1];
348 for (c = 0; c < ntohs (tm->ats_count); c++)
350 type = htonl (ats[c].type);
351 value = htonl (ats[c].value);
352 set_metric (tmp, direction, type, value);
355 GNUNET_SERVER_receive_done (client, GNUNET_OK);
359 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
361 struct DelayQueueEntry *dqe = cls;
362 struct DelayQueueEntry *next;
363 struct TM_Peer *tmp = dqe->tmp;
364 struct GNUNET_TIME_Relative delay;
368 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
369 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
370 GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
372 next = tmp->send_head;
375 /* More delayed messages */
376 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
377 tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
382 /* Remove from generic queue */
383 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
384 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, dqe);
385 GST_neighbours_send (&dqe->id, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
386 next = generic_dqe_head;
389 /* More delayed messages */
390 delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
391 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
400 * Adapter function between transport's send function and transport plugins
402 * @param target the peer the message to send to
403 * @param msg the message received
404 * @param msg_size message size
405 * @param timeout timeout
406 * @param cont the continuation to call after sending
407 * @param cont_cls cls for continuation
410 GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg,
411 size_t msg_size, struct GNUNET_TIME_Relative timeout,
412 GST_NeighbourSendContinuation cont, void *cont_cls)
415 struct DelayQueueEntry *dqe;
416 struct GNUNET_TIME_Relative delay;
418 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &target->hashPubKey)))
420 /* Manipulate here */
422 if (UINT32_MAX != find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
424 /* We have a delay */
425 delay.rel_value = find_metric(tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
426 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
429 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
431 dqe->cont_cls = cont_cls;
433 dqe->msg_size = msg_size;
434 dqe->timeout = timeout;
435 memcpy (dqe->msg, msg, msg_size);
436 GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
437 if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
438 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
442 else if (UINT32_MAX != find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND))
444 /* We have a delay */
445 delay.rel_value = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_SEND);
446 dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
449 dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
451 dqe->cont_cls = cont_cls;
453 dqe->msg_size = msg_size;
454 dqe->timeout = timeout;
455 memcpy (dqe->msg, msg, msg_size);
456 GNUNET_CONTAINER_DLL_insert_tail (generic_dqe_head, generic_dqe_tail, dqe);
457 if (GNUNET_SCHEDULER_NO_TASK == generic_send_delay_task)
458 generic_send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
463 GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
468 * Function that will be called to manipulate ATS information according to
469 * current manipulation settings
471 * @param peer the peer
472 * @param address binary address
473 * @param session the session
474 * @param ats the ats information
475 * @param ats_count the number of ats information
477 struct GNUNET_ATS_Information *
478 GST_manipulation_manipulate_metrics (const struct GNUNET_PeerIdentity *peer,
479 const struct GNUNET_HELLO_Address *address,
480 struct Session *session,
481 const struct GNUNET_ATS_Information *ats,
484 struct GNUNET_ATS_Information *ats_new = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *ats_count);
489 tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey);
491 for (d = 0; d < ats_count; d++)
497 m_tmp = find_metric (tmp, ntohl(ats[d].type), TM_RECEIVE);
498 g_tmp = find_metric (&man_handle.general, ntohl(ats[d].type), TM_RECEIVE);
500 if (UINT32_MAX != g_tmp)
501 ats_new[d].value = htonl(g_tmp);
502 if (UINT32_MAX != m_tmp)
503 ats_new[d].value = htonl(m_tmp);
511 * Adapter function between transport plugins and transport receive function
512 * manipulation delays for next send.
514 * @param cls the closure for transport
515 * @param peer the peer the message was received from
516 * @param message the message received
517 * @param session the session the message was received on
518 * @param sender_address the sender address
519 * @param sender_address_len the length of the sender address
520 * @return manipulated delay for next receive
522 struct GNUNET_TIME_Relative
523 GST_manipulation_recv (void *cls,
524 const struct GNUNET_PeerIdentity *peer,
525 const struct GNUNET_MessageHeader *message,
526 struct Session *session,
527 const char *sender_address,
528 uint16_t sender_address_len)
531 uint32_t p_recv_delay;
532 uint32_t g_recv_delay;
533 struct GNUNET_TIME_Relative quota_delay;
534 struct GNUNET_TIME_Relative m_delay;
536 g_recv_delay = find_metric (&man_handle.general, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
537 if ((g_recv_delay >= GNUNET_TIME_UNIT_ZERO.rel_value) && (UINT32_MAX != g_recv_delay))
538 m_delay.rel_value = g_recv_delay; /* Global delay */
540 m_delay = GNUNET_TIME_UNIT_ZERO;
542 if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (man_handle.peers, &peer->hashPubKey)))
544 /* Manipulate receive delay */
545 p_recv_delay = find_metric (tmp, GNUNET_ATS_QUALITY_NET_DELAY, TM_RECEIVE);
546 if (UINT32_MAX != p_recv_delay)
547 m_delay.rel_value = p_recv_delay; /* Peer specific delay */
550 quota_delay = GST_receive_callback (cls, peer, message,
551 session, sender_address, sender_address_len);
552 if (quota_delay.rel_value > m_delay.rel_value)
560 * Initialize traffic manipulation
562 * @param GST_cfg configuration handle
565 GST_manipulation_init (const struct GNUNET_CONFIGURATION_Handle *GST_cfg)
567 unsigned long long tmp;
569 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
570 "transport", "MANIPULATE_DISTANCE_IN", &tmp))
572 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting inbound distance_in to %u\n",
573 (unsigned long long) tmp);
574 set_metric (&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
577 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
578 "transport", "MANIPULATE_DISTANCE_OUT", &tmp))
580 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setting outbound distance_in to %u\n",
581 (unsigned long long) tmp);
582 set_metric (&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DISTANCE, tmp);
585 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
586 "transport", "MANIPULATE_DELAY_IN", &tmp))
588 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying inbound traffic for %llu ms\n",
589 (unsigned long long) tmp);
590 set_metric (&man_handle.general, TM_RECEIVE, GNUNET_ATS_QUALITY_NET_DELAY, tmp);
594 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (GST_cfg,
595 "transport", "MANIPULATE_DELAY_OUT", &tmp))
597 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Delaying outbound traffic for %llu ms\n",
598 (unsigned long long) tmp);
599 set_metric (&man_handle.general, TM_SEND, GNUNET_ATS_QUALITY_NET_DELAY, tmp);
602 man_handle.peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
607 free_tmps (void *cls,
608 const struct GNUNET_HashCode * key,
611 struct DelayQueueEntry *dqe;
612 struct DelayQueueEntry *next;
615 struct TM_Peer *tmp = (struct TM_Peer *) value;
616 GNUNET_CONTAINER_multihashmap_remove (man_handle.peers, key, value);
618 next = tmp->send_head;
619 while (NULL != (dqe = next))
622 GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
625 if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
627 GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
628 tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
637 * Stop traffic manipulation
640 GST_manipulation_stop ()
642 struct DelayQueueEntry *cur;
643 struct DelayQueueEntry *next;
644 GNUNET_CONTAINER_multihashmap_iterate (man_handle.peers, &free_tmps,NULL);
645 GNUNET_CONTAINER_multihashmap_destroy (man_handle.peers);
647 next = generic_dqe_head;
648 while (NULL != (cur = next))
651 GNUNET_CONTAINER_DLL_remove (generic_dqe_head, generic_dqe_tail, cur);
654 if (GNUNET_SCHEDULER_NO_TASK != generic_send_delay_task)
656 GNUNET_SCHEDULER_cancel (generic_send_delay_task);
657 generic_send_delay_task = GNUNET_SCHEDULER_NO_TASK;
660 free_metric (&man_handle.general);
661 man_handle.peers = NULL;
665 /* end of file gnunet-service-transport_manipulation.c */