changes
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_simplistic.c
1 /*
2      This file is part of GNUnet.
3      (C) 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 ats/gnunet-service-ats_addresses_simplistic.h
23  * @brief ats simplistic ressource assignment
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet_statistics_service.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "ats-simplistic",__VA_ARGS__)
33
34 /**
35  * A handle for the simplistic solver
36  */
37 struct GAS_SIMPLISTIC_Handle
38 {
39
40   unsigned int active_addresses;
41
42   unsigned int networks;
43
44   /**
45    * Network type array
46    *
47    * quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
48    *
49    */
50   int *quota_net;
51
52   /**
53    * Array of inbound quotas
54    *
55    */
56   unsigned long long *total_quota_in;
57
58   /**
59    * Array of outbound quotas
60    *
61    */
62   unsigned long long *total_quota_out;
63
64   /**
65    * Active addresses per network type
66    */
67   unsigned int *active_addresses_per_net;
68 };
69
70 /**
71  * Init the simplistic problem solving component
72  *
73  * Quotas:
74  * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
75  * out_quota[i] contains outbound quota for network type i
76  * in_quota[i] contains inbound quota for network type i
77  *
78  * Example
79  * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
80  * network[2]   == GNUNET_ATS_NET_LAN
81  * out_quota[2] == 65353
82  * in_quota[2]  == 65353
83  *
84  * @param cfg configuration handle
85  * @param stats the GNUNET_STATISTICS handle
86  * @param network array of GNUNET_ATS_NetworkType with length dest_length
87  * @param out_quota array of outbound quotas
88  * param in_quota array of outbound quota
89  * @return handle for the solver on success, NULL on fail
90  */
91 void *
92 GAS_simplistic_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
93                      const struct GNUNET_STATISTICS_Handle *stats,
94                      int *network,
95                      unsigned long long *out_quota,
96                      unsigned long long *in_quota,
97                      int dest_length)
98 {
99   struct GAS_SIMPLISTIC_Handle *solver = GNUNET_malloc (sizeof (struct GAS_SIMPLISTIC_Handle));
100
101   solver->networks = dest_length;
102
103   solver->quota_net = GNUNET_malloc (dest_length * sizeof (int));
104   memcpy (solver->quota_net, network, dest_length * sizeof (int));
105
106   solver->total_quota_in  = GNUNET_malloc (dest_length * sizeof (unsigned long long));
107   memcpy (solver->total_quota_in, in_quota, dest_length * sizeof (int));
108
109   solver->total_quota_out = GNUNET_malloc (dest_length * sizeof (unsigned long long));
110   memcpy (solver->total_quota_out, out_quota, dest_length * sizeof (unsigned long long));
111
112   solver->active_addresses_per_net = GNUNET_malloc (dest_length * sizeof (unsigned int));
113
114   return solver;
115 }
116
117
118 /**
119  * Shutdown the simplistic problem solving component
120  *
121  * @param solver the respective handle to shutdown
122  */
123 void
124 GAS_simplistic_done (void *solver)
125 {
126   struct GAS_SIMPLISTIC_Handle *s = solver;
127   GNUNET_assert (s != NULL);
128   GNUNET_free (s->quota_net);
129   GNUNET_free (s->total_quota_in);
130   GNUNET_free (s->total_quota_out);
131   GNUNET_free (s->active_addresses_per_net);
132   GNUNET_free (s);
133 }
134
135 static void
136 update_quota (struct GAS_SIMPLISTIC_Handle *s, unsigned int net)
137 {
138   unsigned long long quota_in;
139   unsigned long long quota_out;
140
141   quota_in = s->total_quota_in[net] / s->active_addresses_per_net[net];
142   quota_out = s->total_quota_out[net] / s->active_addresses_per_net[net];
143
144   LOG (GNUNET_ERROR_TYPE_DEBUG,
145               "New quota for network type %u (in/out): %llu/%llu \n",
146               net, quota_in, quota_out);
147 }
148
149 /**
150  * Add a single address to the solve
151  *
152  * @param solver the solver Handle
153  * @param addresses the address hashmap containing all addresses
154  * @param address the address to add
155  */
156 void
157 GAS_simplistic_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
158 {
159   struct GAS_SIMPLISTIC_Handle *s = solver;
160   GNUNET_assert (NULL != s);
161   int c;
162   for (c = 0; c < s->networks; c++)
163   {
164       if (address->atsp_network_type == s->quota_net[c])
165       {
166           s->active_addresses_per_net[c] ++;
167           LOG (GNUNET_ERROR_TYPE_DEBUG,
168                       "Adding new address for network type %u (now %u total)\n",
169                       address->atsp_network_type,
170                       s->active_addresses_per_net[c]);
171           break;
172       }
173   }
174
175   /* Update quota for this network type */
176   update_quota (s, c);
177 }
178
179
180
181 /**
182  * Updates a single address in the solve
183  *
184  * @param solver the solver Handle
185  * @param addresses the address hashmap containing all addresses
186  * @param address the update address
187  */
188 void
189 GAS_simplistic_address_update (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
190 {
191 #if 0
192   struct GAS_SIMPLISTIC_Handle *s = solver;
193   GNUNET_assert (NULL != s);
194   int c;
195   for (c = 0; c < s->networks; c++)
196   {
197       if (address->atsp_network_type == s->quota_net[c])
198       {
199           LOG (GNUNET_ERROR_TYPE_DEBUG,
200                       "Updating address for network type %u (%u total)\n",
201                       address->atsp_network_type,
202                       s->active_addresses_per_net[c]);
203           break;
204       }
205   }
206
207   /* Update quota for this network type */
208   update_quota (s, c);
209 #endif
210 }
211
212
213 /**
214  * Remove an address from the solver
215  *
216  * @param solver the solver handle
217  * @param addresses the address hashmap containing all addresses
218  * @param address the address to remove
219  */
220 void
221 GAS_simplistic_address_delete (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
222 {
223 #if 0
224   struct GAS_SIMPLISTIC_Handle *s = solver;
225   GNUNET_assert (NULL != s);
226   int c;
227   for (c = 0; c < s->networks; c++)
228   {
229       if (address->atsp_network_type == s->quota_net[c])
230       {
231           GNUNET_assert (s->active_addresses_per_net[c] > 0);
232           s->active_addresses_per_net[c] --;
233           LOG (GNUNET_ERROR_TYPE_DEBUG,
234                       "Deleting address for network type %u (now %u total)\n",
235                       address->atsp_network_type,
236                       s->active_addresses_per_net[c]);
237           break;
238       }
239   }
240
241   /* Update quota for this network type */
242   update_quota (s, c);
243 #endif
244 }
245
246
247
248 /**
249  * Find a "good" address to use for a peer.  If we already have an existing
250  * address, we stick to it.  Otherwise, we pick by lowest distance and then
251  * by lowest latency.
252  *
253  * @param cls the 'struct ATS_Address**' where we store the result
254  * @param key unused
255  * @param value another 'struct ATS_Address*' to consider using
256  * @return GNUNET_OK (continue to iterate)
257  */
258 static int
259 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
260 {
261   struct ATS_Address **previous_p = cls;
262   struct ATS_Address *current = (struct ATS_Address *) value;
263   struct ATS_Address *previous = *previous_p;
264   struct GNUNET_TIME_Absolute now;
265
266   now = GNUNET_TIME_absolute_get();
267
268   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
269   {
270     /* This address is blocked for suggestion */
271     LOG (GNUNET_ERROR_TYPE_DEBUG,
272                 "Address %p blocked for suggestion for %llu ms \n",
273                 current,
274                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
275     return GNUNET_OK;
276   }
277
278   if (NULL != previous)
279   {
280     if ((0 == strcmp (previous->plugin, "tcp")) &&
281         (0 == strcmp (current->plugin, "tcp")))
282     {
283       if ((0 != previous->addr_len) &&
284           (0 == current->addr_len))
285       {
286         /* saved address was an outbound address, but we have an inbound address */
287         *previous_p = current;
288         return GNUNET_OK;
289       }
290       if (0 == previous->addr_len)
291       {
292         /* saved address was an inbound address, so do not overwrite */
293         return GNUNET_OK;
294       }
295     }
296   }
297
298   if (NULL == previous)
299   {
300     *previous_p = current;
301     return GNUNET_OK;
302   }
303   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
304       (ntohl (current->assigned_bw_in.value__) > 0))
305   {
306     /* stick to existing connection */
307     *previous_p = current;
308     return GNUNET_OK;
309   }
310   if (previous->atsp_distance > current->atsp_distance)
311   {
312     /* user shorter distance */
313     *previous_p = current;
314     return GNUNET_OK;
315   }
316   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
317   {
318     /* user lower latency */
319     *previous_p = current;
320     return GNUNET_OK;
321   }
322   /* don't care */
323   return GNUNET_OK;
324 }
325
326 static int
327 update_bw_simple_it (void *cls, const struct GNUNET_HashCode * key, void *value)
328 {
329   struct GAS_SIMPLISTIC_Handle *s = cls;
330   struct ATS_Address *aa = value;
331
332   if (GNUNET_YES != aa->active)
333     return GNUNET_OK;
334   GNUNET_assert (s->active_addresses > 0);
335
336
337   /* Simple method */
338
339   aa->assigned_bw_in.value__ = htonl (UINT32_MAX / s->active_addresses);
340   aa->assigned_bw_out.value__ = htonl (UINT32_MAX / s->active_addresses);
341
342   return GNUNET_OK;
343 }
344
345 /**
346  * Some (significant) input changed, recalculate bandwidth assignment
347  * for all peers.
348  */
349 static void
350 recalculate_assigned_bw (void *solver,
351                          struct GNUNET_CONTAINER_MultiHashMap * addresses)
352 {
353   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354               "Recalculating bandwidth for all active connections\n");
355   GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, solver);
356 }
357
358
359
360 /**
361  * Get the prefered address for a specific peer
362  *
363  * @param solver the solver handle
364  * @param addresses the address hashmap containing all addresses
365  * @param peer the identity of the peer
366  */
367 const struct ATS_Address *
368 GAS_simplistic_get_preferred_address (void *solver,
369                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
370                                const struct GNUNET_PeerIdentity *peer)
371 {
372   struct GAS_SIMPLISTIC_Handle *s = solver;
373   struct ATS_Address *aa;
374
375   GNUNET_assert (s != NULL);
376   aa = NULL;
377   /* Get address with: stick to current address, lower distance, lower latency */
378   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
379                                               &find_address_it, &aa);
380   if (NULL == aa)
381     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
382   else
383   {
384     LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
385
386     if (GNUNET_NO == aa->active)
387     {
388       aa->active = GNUNET_YES;
389       s->active_addresses++;
390       recalculate_assigned_bw (s, addresses);
391     }
392   }
393
394   return aa;
395 }
396
397
398 /**
399  * Changes the preferences for a peer in the problem
400  *
401  * @param solver the solver handle
402  * @param peer the peer to change the preference for
403  * @param kind the kind to change the preference
404  * @param score the score
405  */
406 void
407 GAS_simplistic_address_change_preference (void *solver,
408                                    const struct GNUNET_PeerIdentity *peer,
409                                    enum GNUNET_ATS_PreferenceKind kind,
410                                    float score)
411 {
412   /* FIXME : implement this */
413 }
414
415 /* end of gnunet-service-ats_addresses_simplistic.c */