mod
[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 *quota_in;
57
58   /**
59    * Array of outbound quotas
60    *
61    */
62   unsigned long long *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->quota_in  = GNUNET_malloc (dest_length * sizeof (unsigned long long));
107   memcpy (solver->quota_in, in_quota, dest_length * sizeof (int));
108
109   solver->quota_out = GNUNET_malloc (dest_length * sizeof (unsigned long long));
110   memcpy (solver->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->quota_in);
130   GNUNET_free (s->quota_out);
131   GNUNET_free (s->active_addresses_per_net);
132   GNUNET_free (s);
133 }
134
135 /**
136  * Add a single address to the solve
137  *
138  * @param solver the solver Handle
139  * @param addresses the address hashmap containing all addresses
140  * @param address the address to add
141  */
142 void
143 GAS_simplistic_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
144 {
145
146
147 }
148
149
150
151 /**
152  * Updates a single address in the solve
153  *
154  * @param solver the solver Handle
155  * @param addresses the address hashmap containing all addresses
156  * @param address the update address
157  */
158 void
159 GAS_simplistic_address_update (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
160 {
161
162
163 }
164
165
166 /**
167  * Remove an address from the solver
168  *
169  * @param solver the solver handle
170  * @param addresses the address hashmap containing all addresses
171  * @param address the address to remove
172  */
173 void
174 GAS_simplistic_address_delete (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
175 {
176
177 }
178
179
180
181 /**
182  * Find a "good" address to use for a peer.  If we already have an existing
183  * address, we stick to it.  Otherwise, we pick by lowest distance and then
184  * by lowest latency.
185  *
186  * @param cls the 'struct ATS_Address**' where we store the result
187  * @param key unused
188  * @param value another 'struct ATS_Address*' to consider using
189  * @return GNUNET_OK (continue to iterate)
190  */
191 static int
192 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
193 {
194   struct ATS_Address **previous_p = cls;
195   struct ATS_Address *current = (struct ATS_Address *) value;
196   struct ATS_Address *previous = *previous_p;
197   struct GNUNET_TIME_Absolute now;
198
199   now = GNUNET_TIME_absolute_get();
200
201   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
202   {
203     /* This address is blocked for suggestion */
204     LOG (GNUNET_ERROR_TYPE_DEBUG,
205                 "Address %p blocked for suggestion for %llu ms \n",
206                 current,
207                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
208     return GNUNET_OK;
209   }
210
211   if (NULL != previous)
212   {
213     if ((0 == strcmp (previous->plugin, "tcp")) &&
214         (0 == strcmp (current->plugin, "tcp")))
215     {
216       if ((0 != previous->addr_len) &&
217           (0 == current->addr_len))
218       {
219         /* saved address was an outbound address, but we have an inbound address */
220         *previous_p = current;
221         return GNUNET_OK;
222       }
223       if (0 == previous->addr_len)
224       {
225         /* saved address was an inbound address, so do not overwrite */
226         return GNUNET_OK;
227       }
228     }
229   }
230
231   if (NULL == previous)
232   {
233     *previous_p = current;
234     return GNUNET_OK;
235   }
236   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
237       (ntohl (current->assigned_bw_in.value__) > 0))
238   {
239     /* stick to existing connection */
240     *previous_p = current;
241     return GNUNET_OK;
242   }
243   if (previous->atsp_distance > current->atsp_distance)
244   {
245     /* user shorter distance */
246     *previous_p = current;
247     return GNUNET_OK;
248   }
249   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
250   {
251     /* user lower latency */
252     *previous_p = current;
253     return GNUNET_OK;
254   }
255   /* don't care */
256   return GNUNET_OK;
257 }
258
259 static int
260 update_bw_simple_it (void *cls, const struct GNUNET_HashCode * key, void *value)
261 {
262   struct GAS_SIMPLISTIC_Handle *s = cls;
263   struct ATS_Address *aa = value;
264
265   if (GNUNET_YES != aa->active)
266     return GNUNET_OK;
267   GNUNET_assert (s->active_addresses > 0);
268
269
270   /* Simple method */
271
272   aa->assigned_bw_in.value__ = htonl (UINT32_MAX / s->active_addresses);
273   aa->assigned_bw_out.value__ = htonl (UINT32_MAX / s->active_addresses);
274
275   return GNUNET_OK;
276 }
277
278 /**
279  * Some (significant) input changed, recalculate bandwidth assignment
280  * for all peers.
281  */
282 static void
283 recalculate_assigned_bw (void *solver,
284                          struct GNUNET_CONTAINER_MultiHashMap * addresses)
285 {
286   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287               "Recalculating bandwidth for all active connections\n");
288   GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, solver);
289 }
290
291
292
293 /**
294  * Get the prefered address for a specific peer
295  *
296  * @param solver the solver handle
297  * @param addresses the address hashmap containing all addresses
298  * @param peer the identity of the peer
299  */
300 const struct ATS_Address *
301 GAS_simplistic_get_preferred_address (void *solver,
302                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
303                                const struct GNUNET_PeerIdentity *peer)
304 {
305   struct GAS_SIMPLISTIC_Handle *s = solver;
306   struct ATS_Address *aa;
307
308   GNUNET_assert (s != NULL);
309   aa = NULL;
310   /* Get address with: stick to current address, lower distance, lower latency */
311   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
312                                               &find_address_it, &aa);
313   if (NULL == aa)
314     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
315   else
316   {
317     LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
318
319     if (GNUNET_NO == aa->active)
320     {
321       aa->active = GNUNET_YES;
322       s->active_addresses++;
323       recalculate_assigned_bw (s, addresses);
324     }
325   }
326
327   return aa;
328 }
329
330
331 /**
332  * Changes the preferences for a peer in the problem
333  *
334  * @param solver the solver handle
335  * @param peer the peer to change the preference for
336  * @param kind the kind to change the preference
337  * @param score the score
338  */
339 void
340 GAS_simplistic_address_change_preference (void *solver,
341                                    const struct GNUNET_PeerIdentity *peer,
342                                    enum GNUNET_ATS_PreferenceKind kind,
343                                    float score)
344 {
345   /* FIXME : implement this */
346 }
347
348 /* end of gnunet-service-ats_addresses_simplistic.c */