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   /**
43    * Network type array
44    *
45    * quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
46    *
47    */
48   int *quota_net;
49
50   /**
51    * Array of inbound quotas
52    *
53    */
54   unsigned long long *quota_in;
55
56   /**
57    * Array of outbound quotas
58    *
59    */
60   unsigned long long *quota_out;
61
62   /**
63    * Active addresses per network type
64    */
65   unsigned int *active_addresses_per_net;
66 };
67
68 /**
69  * Init the simplistic problem solving component
70  *
71  * Quotas:
72  * network[i] contains the network type as type GNUNET_ATS_NetworkType[i]
73  * out_quota[i] contains outbound quota for network type i
74  * in_quota[i] contains inbound quota for network type i
75  *
76  * Example
77  * network = {GNUNET_ATS_NET_UNSPECIFIED, GNUNET_ATS_NET_LOOPBACK, GNUNET_ATS_NET_LAN, GNUNET_ATS_NET_WAN, GNUNET_ATS_NET_WLAN}
78  * network[2]   == GNUNET_ATS_NET_LAN
79  * out_quota[2] == 65353
80  * in_quota[2]  == 65353
81  *
82  * @param cfg configuration handle
83  * @param stats the GNUNET_STATISTICS handle
84  * @param network array of GNUNET_ATS_NetworkType with length dest_length
85  * @param out_quota array of outbound quotas
86  * param in_quota array of outbound quota
87  * @return handle for the solver on success, NULL on fail
88  */
89 void *
90 GAS_simplistic_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
91                      const struct GNUNET_STATISTICS_Handle *stats,
92                      int *network,
93                      unsigned long long *out_quota,
94                      unsigned long long *in_quota,
95                      int dest_length)
96 {
97   struct GAS_SIMPLISTIC_Handle *solver = GNUNET_malloc (sizeof (struct GAS_SIMPLISTIC_Handle));
98
99   solver->quota_net = GNUNET_malloc (dest_length * sizeof (int));
100   memcpy (solver->quota_net, network, dest_length * sizeof (int));
101
102   solver->quota_in  = GNUNET_malloc (dest_length * sizeof (unsigned long long));
103   memcpy (solver->quota_in, in_quota, dest_length * sizeof (int));
104
105   solver->quota_out = GNUNET_malloc (dest_length * sizeof (unsigned long long));
106   memcpy (solver->quota_out, out_quota, dest_length * sizeof (unsigned long long));
107
108   solver->active_addresses_per_net = GNUNET_malloc (dest_length * sizeof (unsigned int));
109
110   return solver;
111 }
112
113
114 /**
115  * Shutdown the simplistic problem solving component
116  *
117  * @param solver the respective handle to shutdown
118  */
119 void
120 GAS_simplistic_done (void *solver)
121 {
122   struct GAS_SIMPLISTIC_Handle *s = solver;
123   GNUNET_assert (s != NULL);
124   GNUNET_free (s->quota_net);
125   GNUNET_free (s->quota_in);
126   GNUNET_free (s->quota_out);
127   GNUNET_free (s->active_addresses_per_net);
128   GNUNET_free (s);
129 }
130
131 /**
132  * Updates a single address in the solve
133  *
134  * @param solver the solver Handle
135  * @param addresses the address hashmap containing all addresses
136  * @param address the update address
137  */
138 void
139 GAS_simplistic_address_update (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
140 {
141
142 }
143
144
145 /**
146  * Remove an address from the solver
147  *
148  * @param solver the solver handle
149  * @param addresses the address hashmap containing all addresses
150  * @param address the address to remove
151  */
152 void
153 GAS_simplistic_address_delete (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
154 {
155
156 }
157
158
159
160 /**
161  * Find a "good" address to use for a peer.  If we already have an existing
162  * address, we stick to it.  Otherwise, we pick by lowest distance and then
163  * by lowest latency.
164  *
165  * @param cls the 'struct ATS_Address**' where we store the result
166  * @param key unused
167  * @param value another 'struct ATS_Address*' to consider using
168  * @return GNUNET_OK (continue to iterate)
169  */
170 static int
171 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
172 {
173   struct ATS_Address **previous_p = cls;
174   struct ATS_Address *current = (struct ATS_Address *) value;
175   struct ATS_Address *previous = *previous_p;
176   struct GNUNET_TIME_Absolute now;
177
178   now = GNUNET_TIME_absolute_get();
179
180   if (current->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, current->blocked_until).abs_value)
181   {
182     /* This address is blocked for suggestion */
183     LOG (GNUNET_ERROR_TYPE_DEBUG,
184                 "Address %p blocked for suggestion for %llu ms \n",
185                 current,
186                 GNUNET_TIME_absolute_get_difference(now, current->blocked_until).rel_value);
187     return GNUNET_OK;
188   }
189
190   if (NULL != previous)
191   {
192     if ((0 == strcmp (previous->plugin, "tcp")) &&
193         (0 == strcmp (current->plugin, "tcp")))
194     {
195       if ((0 != previous->addr_len) &&
196           (0 == current->addr_len))
197       {
198         /* saved address was an outbound address, but we have an inbound address */
199         *previous_p = current;
200         return GNUNET_OK;
201       }
202       if (0 == previous->addr_len)
203       {
204         /* saved address was an inbound address, so do not overwrite */
205         return GNUNET_OK;
206       }
207     }
208   }
209
210   if (NULL == previous)
211   {
212     *previous_p = current;
213     return GNUNET_OK;
214   }
215   if ((ntohl (previous->assigned_bw_in.value__) == 0) &&
216       (ntohl (current->assigned_bw_in.value__) > 0))
217   {
218     /* stick to existing connection */
219     *previous_p = current;
220     return GNUNET_OK;
221   }
222   if (previous->atsp_distance > current->atsp_distance)
223   {
224     /* user shorter distance */
225     *previous_p = current;
226     return GNUNET_OK;
227   }
228   if (previous->atsp_latency.rel_value > current->atsp_latency.rel_value)
229   {
230     /* user lower latency */
231     *previous_p = current;
232     return GNUNET_OK;
233   }
234   /* don't care */
235   return GNUNET_OK;
236 }
237
238 static int
239 update_bw_simple_it (void *cls, const struct GNUNET_HashCode * key, void *value)
240 {
241   struct GAS_SIMPLISTIC_Handle *s = cls;
242   struct ATS_Address *aa = value;
243
244   if (GNUNET_YES != aa->active)
245     return GNUNET_OK;
246   GNUNET_assert (s->active_addresses > 0);
247
248
249   /* Simple method */
250
251   aa->assigned_bw_in.value__ = htonl (UINT32_MAX / s->active_addresses);
252   aa->assigned_bw_out.value__ = htonl (UINT32_MAX / s->active_addresses);
253
254   return GNUNET_OK;
255 }
256
257 /**
258  * Some (significant) input changed, recalculate bandwidth assignment
259  * for all peers.
260  */
261 static void
262 recalculate_assigned_bw (void *solver,
263                          struct GNUNET_CONTAINER_MultiHashMap * addresses)
264 {
265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266               "Recalculating bandwidth for all active connections\n");
267   GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, solver);
268 }
269
270
271
272 /**
273  * Get the prefered address for a specific peer
274  *
275  * @param solver the solver handle
276  * @param addresses the address hashmap containing all addresses
277  * @param peer the identity of the peer
278  */
279 const struct ATS_Address *
280 GAS_simplistic_get_preferred_address (void *solver,
281                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
282                                const struct GNUNET_PeerIdentity *peer)
283 {
284   struct GAS_SIMPLISTIC_Handle *s = solver;
285   struct ATS_Address *aa;
286
287   GNUNET_assert (s != NULL);
288   aa = NULL;
289   /* Get address with: stick to current address, lower distance, lower latency */
290   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
291                                               &find_address_it, &aa);
292   if (NULL == aa)
293     LOG (GNUNET_ERROR_TYPE_DEBUG, "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
294   else
295   {
296     LOG (GNUNET_ERROR_TYPE_DEBUG, "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
297
298     if (GNUNET_NO == aa->active)
299     {
300       aa->active = GNUNET_YES;
301       s->active_addresses++;
302       recalculate_assigned_bw (s, addresses);
303     }
304   }
305
306   return aa;
307 }
308
309
310 /**
311  * Changes the preferences for a peer in the problem
312  *
313  * @param solver the solver handle
314  * @param peer the peer to change the preference for
315  * @param kind the kind to change the preference
316  * @param score the score
317  */
318 void
319 GAS_simplistic_address_change_preference (void *solver,
320                                    const struct GNUNET_PeerIdentity *peer,
321                                    enum GNUNET_ATS_PreferenceKind kind,
322                                    float score)
323 {
324   /* FIXME : implement this */
325 }
326
327 /* end of gnunet-service-ats_addresses_simplistic.c */