error msg
[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 static struct GNUNET_CONTAINER_MultiHashMap *peers;
38
39 #define DELAY 0
40 #define DISTANCE 1
41
42 struct TM_Peer;
43
44 struct DelayQueueEntry
45 {
46         struct DelayQueueEntry *prev;
47         struct DelayQueueEntry *next;
48         struct TM_Peer *tmp;
49         struct GNUNET_TIME_Absolute sent_at;
50         void *msg;
51         size_t msg_size;
52         struct GNUNET_TIME_Relative timeout;
53         GST_NeighbourSendContinuation cont;
54         void *cont_cls;
55 };
56
57 struct TM_Peer
58 {
59         struct GNUNET_PeerIdentity peer;
60         uint32_t metrics [TM_BOTH][GNUNET_ATS_QualityPropertiesCount];
61         GNUNET_SCHEDULER_TaskIdentifier send_delay_task;
62         struct DelayQueueEntry *send_head;
63         struct DelayQueueEntry *send_tail;
64 };
65
66
67
68 static void
69 set_delay(struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
70 {
71         uint32_t val;
72         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n",
73                         "DELAY", GNUNET_i2s(peer),
74                         (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value);
75
76         if (UINT32_MAX == value)
77                 val = UINT32_MAX - 1; /* prevent overflow */
78         else if (0 == value)
79                 val = UINT32_MAX; /* disable */
80         else
81                 val = value;
82
83         switch (direction) {
84                 case TM_BOTH:
85                         tmp->metrics[TM_SEND][DELAY] = val;
86                         tmp->metrics[TM_RECEIVE][DELAY] = val;
87                         break;
88                 case TM_SEND:
89                         tmp->metrics[TM_SEND][DELAY] = val;
90                         break;
91                 case TM_RECEIVE:
92                         tmp->metrics[TM_RECEIVE][DELAY] = val;
93                         break;
94                 default:
95                         break;
96         }
97
98 }
99
100 static void
101 set_distance (struct TM_Peer *tmp, struct GNUNET_PeerIdentity *peer, int direction, uint32_t value)
102 {
103         uint32_t val;
104         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Set traffic metrics %s for peer `%s' in direction %s to %u\n",
105                         "DISTANCE", GNUNET_i2s(peer),
106                         (TM_BOTH == direction) ? "BOTH" : (TM_SEND == direction) ? "SEND": "RECEIVE", value);
107
108         if (UINT32_MAX == value)
109                 val = UINT32_MAX - 1; /* prevent overflow */
110         else if (0 == value)
111                 val = UINT32_MAX; /* disable */
112         else
113                 val = value;
114
115         switch (direction) {
116         case TM_BOTH:
117                 tmp->metrics[TM_SEND][DISTANCE] = val;
118                 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
119                 break;
120         case TM_SEND:
121                 tmp->metrics[TM_SEND][DISTANCE] = val;
122                 break;
123         case TM_RECEIVE:
124                 tmp->metrics[TM_RECEIVE][DISTANCE] = val;
125                 break;
126         default:
127                 break;
128         }
129 }
130
131 void
132 GST_manipulation_set_metric (void *cls, struct GNUNET_SERVER_Client *client,
133     const struct GNUNET_MessageHeader *message)
134 {
135         struct TrafficMetricMessage *tm = (struct TrafficMetricMessage *) message;
136         struct GNUNET_ATS_Information *ats;
137         struct TM_Peer *tmp;
138         uint32_t type;
139         uint32_t value;
140         int c;
141         int c2;
142
143         if (0 == ntohs (tm->ats_count))
144           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
145
146         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received traffic metrics for peer `%s'\n",
147                         GNUNET_i2s(&tm->peer));
148
149         if (NULL == (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &tm->peer.hashPubKey)))
150         {
151                         tmp = GNUNET_malloc (sizeof (struct TM_Peer));
152                         tmp->peer = (tm->peer);
153                         for (c = 0; c < TM_BOTH; c++)
154                         {
155                                         for (c2 = 0; c2 < GNUNET_ATS_QualityPropertiesCount; c2++)
156                                         {
157                                                         tmp->metrics[c][c2] = UINT32_MAX;
158                                         }
159                         }
160                         GNUNET_CONTAINER_multihashmap_put (peers, &tm->peer.hashPubKey, tmp, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
161         }
162
163         ats = (struct GNUNET_ATS_Information *) &tm[1];
164         for (c = 0; c < ntohs (tm->ats_count); c++)
165         {
166                         type = htonl (ats[c].type);
167                         value = htonl (ats[c].value);
168                         switch (type) {
169                                 case GNUNET_ATS_QUALITY_NET_DELAY:
170                                         set_delay (tmp, &tm->peer, ntohs (tm->direction), value);
171                                         break;
172                                 case GNUNET_ATS_QUALITY_NET_DISTANCE:
173                                         set_distance (tmp, &tm->peer, ntohs (tm->direction), value);
174                                         break;
175                                 default:
176                                         break;
177                         }
178         }
179
180   GNUNET_SERVER_receive_done (client, GNUNET_OK);
181 }
182
183 static void
184 send_delayed (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
185 {
186         struct DelayQueueEntry *dqe = cls;
187         struct DelayQueueEntry *next;
188         struct TM_Peer *tmp = dqe->tmp;
189         struct GNUNET_TIME_Relative delay;
190         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
191         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
192         GST_neighbours_send (&tmp->peer, dqe->msg, dqe->msg_size, dqe->timeout, dqe->cont, dqe->cont_cls);
193
194         next = tmp->send_head;
195         if (NULL != next)
196         {
197                         /* More delayed messages */
198                         delay = GNUNET_TIME_absolute_get_remaining (next->sent_at);
199                         tmp->send_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
200         }
201
202         GNUNET_free (dqe);
203 }
204
205 void
206 GST_manipulation_send (const struct GNUNET_PeerIdentity *target, const void *msg,
207     size_t msg_size, struct GNUNET_TIME_Relative timeout,
208     GST_NeighbourSendContinuation cont, void *cont_cls)
209 {
210         struct TM_Peer *tmp;
211         struct DelayQueueEntry *dqe;
212         struct GNUNET_TIME_Relative delay;
213
214         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &target->hashPubKey)))
215         {
216                         /* Manipulate here */
217                         /* Delay */
218                         if (UINT32_MAX != tmp->metrics[TM_SEND][DELAY])
219                         {
220                                         /* We have a delay */
221                                         delay.rel_value = tmp->metrics[TM_SEND][DELAY];
222                                         dqe = GNUNET_malloc (sizeof (struct DelayQueueEntry) + msg_size);
223                                         dqe->tmp = tmp;
224                                         dqe->sent_at = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), delay);
225                                         dqe->cont = cont;
226                                         dqe->cont_cls = cont_cls;
227                                         dqe->msg = &dqe[1];
228                                         dqe->msg_size = msg_size;
229                                         dqe->timeout = timeout;
230                                         memcpy (dqe->msg, msg, msg_size);
231                                         GNUNET_CONTAINER_DLL_insert_tail (tmp->send_head, tmp->send_tail, dqe);
232                                         if (GNUNET_SCHEDULER_NO_TASK == tmp->send_delay_task)
233                                                 tmp->send_delay_task =GNUNET_SCHEDULER_add_delayed (delay, &send_delayed, dqe);
234                                         return;
235                         }
236         }
237         /* Normal sending */
238         GST_neighbours_send (target, msg, msg_size, timeout, cont, cont_cls);
239 }
240
241 struct GNUNET_TIME_Relative
242 GST_manipulation_recv (void *cls, const struct GNUNET_PeerIdentity *peer,
243     const struct GNUNET_MessageHeader *message,
244     const struct GNUNET_ATS_Information *ats,
245     uint32_t ats_count, struct Session *session,
246     const char *sender_address,
247     uint16_t sender_address_len)
248 {
249         struct TM_Peer *tmp;
250         int d;
251         struct GNUNET_ATS_Information ats_new[ats_count];
252         struct GNUNET_TIME_Relative q_delay;
253         struct GNUNET_TIME_Relative m_delay;
254
255         for (d = 0; d < ats_count; d++)
256
257         if (NULL != (tmp = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey)))
258         {
259                         /* Manipulate distance */
260                         for (d = 0; d < ats_count; d++)
261                         {
262                                         ats_new[d] = ats[d];
263                                         /* Set distance */
264                                         if ((ntohl(ats[d].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) &&
265                                                  (UINT32_MAX != tmp->metrics[TM_RECEIVE][DISTANCE]))
266                                                         ats_new[d].value = htonl(tmp->metrics[TM_RECEIVE][DISTANCE]);
267                         }
268                         /* Manipulate receive delay */
269                         if (UINT32_MAX != tmp->metrics[TM_RECEIVE][DELAY])
270                         {
271                                         m_delay.rel_value = tmp->metrics[TM_RECEIVE][DELAY];
272                                         q_delay = GST_receive_callback (cls, peer, message, &ats_new[0], ats_count,
273                                                         session, sender_address, sender_address_len);
274
275                                         if (q_delay.rel_value >= m_delay.rel_value)
276                                         {
277                                                         return q_delay;
278                                         }
279                                         else
280                                         {
281                                                         return m_delay;
282                                         }
283                         }
284                         else
285                                 return GST_receive_callback (cls, peer, message, &ats_new[0], ats_count,
286                                                 session, sender_address, sender_address_len);
287         }
288
289         return GST_receive_callback (cls, peer, message, ats, ats_count,
290                         session, sender_address, sender_address_len);
291 }
292
293 void
294 GST_manipulation_init ()
295 {
296         peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
297 }
298
299 int free_tmps (void *cls,
300                                                          const struct GNUNET_HashCode * key,
301                                                          void *value)
302 {
303         struct DelayQueueEntry *dqe;
304         struct DelayQueueEntry *next;
305         if (NULL != value)
306         {
307                         struct TM_Peer *tmp = (struct TM_Peer *) value;
308                         GNUNET_CONTAINER_multihashmap_remove (peers, key, value);
309                         next = tmp->send_head;
310                         while (NULL != (dqe = next))
311                         {
312                                         next = dqe->next;
313                                         GNUNET_CONTAINER_DLL_remove (tmp->send_head, tmp->send_tail, dqe);
314                                         GNUNET_free (dqe);
315                         }
316                         if (GNUNET_SCHEDULER_NO_TASK != tmp->send_delay_task)
317                         {
318                                         GNUNET_SCHEDULER_cancel (tmp->send_delay_task);
319                                         tmp->send_delay_task = GNUNET_SCHEDULER_NO_TASK;
320                         }
321                         GNUNET_free (tmp);
322         }
323         return GNUNET_OK;
324 }
325
326 void
327 GST_manipulation_stop ()
328 {
329         GNUNET_CONTAINER_multihashmap_iterate (peers, &free_tmps,NULL);
330
331         GNUNET_CONTAINER_multihashmap_destroy (peers);
332         peers = NULL;
333 }
334
335
336 /* end of file gnunet-service-transport_manipulation.c */