restrict to 1 scheduling client
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.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.c
23  * @brief ats service address management
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet-service-ats_addresses.h"
29 #include "gnunet-service-ats_performance.h"
30 #include "gnunet-service-ats_scheduling.h"
31 #include "gnunet-service-ats_reservations.h"
32
33 struct ATS_Address
34 {
35   struct GNUNET_PeerIdentity peer;
36
37   size_t addr_len;
38
39   uint32_t session_id;
40
41   uint32_t ats_count;
42
43   const void * addr;
44
45   char * plugin;
46
47   struct GNUNET_ATS_Information * ats;
48
49   struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_in;
50
51   struct GNUNET_BANDWIDTH_Value32NBO atsp_utilization_out;
52
53   struct GNUNET_TIME_Relative atsp_latency;
54
55   uint32_t atsp_distance;
56
57   uint32_t atsp_cost_wan;
58
59   uint32_t atsp_cost_lan;
60
61   uint32_t atsp_cost_wlan;
62
63   struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_in;
64
65   struct GNUNET_BANDWIDTH_Value32NBO assigned_bw_out;
66
67   struct GNUNET_BANDWIDTH_Value32NBO bw_in;
68
69   struct GNUNET_BANDWIDTH_Value32NBO bw_out;
70
71 };
72
73
74 static struct GNUNET_CONTAINER_MultiHashMap * addresses;
75
76 static unsigned long long total_quota_in;
77
78 static unsigned long long total_quota_out;
79
80 static unsigned int active_addr_count;
81
82
83 struct CompareAddressContext
84 {
85   struct ATS_Address * search;
86   struct ATS_Address * result;
87 };
88
89
90 static void
91 destroy_address (struct ATS_Address *addr)
92 {
93   GNUNET_assert (GNUNET_YES == 
94                  GNUNET_CONTAINER_multihashmap_remove(addresses, 
95                                                       &addr->peer.hashPubKey, 
96                                                       addr));
97   if (ntohl (addr->bw_in.value__) > 0)
98   {
99     active_addr_count--;
100     // FIXME: update address assignment for other peers...
101   }
102   GNUNET_free_non_null (addr->ats);
103   GNUNET_free (addr->plugin);
104   GNUNET_free (addr);
105 }
106
107
108 static int 
109 compare_address_it (void *cls,
110                     const GNUNET_HashCode * key,
111                     void *value)
112 {
113   struct CompareAddressContext * cac = cls;
114   struct ATS_Address * aa = (struct ATS_Address *) value;
115
116   /* compare sessions */
117   if (aa->session_id != cac->search->session_id)
118     return GNUNET_YES;
119
120   if (aa->addr_len != cac->search->addr_len)
121   {
122     return GNUNET_YES;
123   }
124
125   if (0 == strcmp(aa->plugin, cac->search->plugin))
126   {
127     return GNUNET_YES;
128   }
129
130   if (0 == memcmp (aa->addr, cac->search->addr, aa->addr_len))
131   {
132     cac->result = aa;
133     return GNUNET_NO;
134   }
135   return GNUNET_YES;
136 }
137
138
139 struct ATS_Address *
140 find_address (const struct GNUNET_PeerIdentity *peer,
141               struct ATS_Address * addr)
142 {
143   struct CompareAddressContext cac;
144   cac.result = NULL;
145   cac.search = addr;
146
147   GNUNET_CONTAINER_multihashmap_get_multiple(addresses,
148          &peer->hashPubKey,
149          compare_address_it,
150          &cac);
151
152   return cac.result;
153 }
154
155
156 void
157 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
158                       const char *plugin_name,
159                       const void *plugin_addr, size_t plugin_addr_len,
160                       uint32_t session_id,
161                       const struct GNUNET_ATS_Information *atsi,
162                       uint32_t atsi_count)
163 {
164   struct ATS_Address * aa;
165   struct ATS_Address * old;
166
167   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
168   aa->ats = GNUNET_malloc(atsi_count * sizeof (struct GNUNET_ATS_Information));
169   aa->peer = *peer;
170   aa->addr_len = plugin_addr_len;
171   aa->ats_count = atsi_count;
172   memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
173   aa->addr = &aa[1];
174   memcpy (&aa[1], plugin_addr, plugin_addr_len);
175   aa->plugin = GNUNET_strdup (plugin_name);
176   aa->session_id = session_id;
177   old = find_address (peer, aa);
178   if (old == NULL)
179   {
180     GNUNET_assert (GNUNET_OK ==
181                    GNUNET_CONTAINER_multihashmap_put (addresses,
182                                                       &peer->hashPubKey,
183                                                       aa,
184                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
185     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186                 "Added new address for peer `%s' %X\n",
187                 GNUNET_i2s (peer), aa);
188     return;
189   }
190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191               "Updated existing address for peer `%s' %X \n",
192               GNUNET_i2s (peer), old);
193   GNUNET_free_non_null (old->ats);
194   old->ats = NULL;
195   old->ats_count = 0;
196   old->ats = aa->ats;
197   old->ats_count = aa->ats_count;
198   GNUNET_free (aa->plugin);
199   GNUNET_free (aa);
200 }
201
202
203 void
204 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
205                        const char *plugin_name,
206                        const void *plugin_addr, size_t plugin_addr_len,
207                        uint32_t session_id)
208 {
209
210   struct ATS_Address aa;
211   struct ATS_Address *res;
212
213   aa.peer = *peer;
214   aa.addr_len = plugin_addr_len;
215   aa.addr = plugin_addr;
216   aa.plugin = (char*) plugin_name;
217   aa.session_id = session_id;
218
219   res = find_address (peer, &aa);
220   if (res == NULL)
221   {
222     /* we don't even know this one, can this happen? */
223     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224                 "Asked to delete unknown address for peer `%s'\n",
225                 GNUNET_i2s (peer));
226     return; 
227   }
228   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
229               "Deleting address for peer `%s': `%s'\n",
230               GNUNET_i2s (peer), plugin_name);
231   destroy_address (res);
232 }
233
234
235 void
236 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
237 {
238   struct ATS_Address * aa;
239
240   aa = GNUNET_CONTAINER_multihashmap_get (addresses, &peer->hashPubKey);
241   if (aa == NULL)
242   {
243     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244                 "Cannot suggest address for peer `%s'\n",
245                 GNUNET_i2s (peer));
246     return; 
247   }
248   /* FIXME: ensure that we don't do this multiple times per peer! */
249   if (ntohl (aa->bw_in.value__) == 0)
250   {
251     active_addr_count++;
252     aa->bw_in.value__ = htonl (total_quota_in / active_addr_count);
253     aa->bw_out.value__ = htonl (total_quota_out / active_addr_count);
254     /* FIXME: update bw assignments for other addresses... */
255   }
256   GAS_reservations_set_bandwidth (peer,
257                                   aa->bw_in);
258   GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, 
259                                               aa->addr, aa->addr_len, 
260                                               aa->session_id, 
261                                               aa->ats, aa->ats_count, 
262                                               aa->bw_out, aa->bw_in);
263   GAS_performance_notify_clients (peer, aa->plugin, 
264                                   aa->addr, aa->addr_len, 
265                                   aa->ats, aa->ats_count, 
266                                   aa->bw_out, aa->bw_in);
267 }
268
269
270 // FIXME: this function should likely end up in the LP-subsystem and
271 // not with 'addresses' in the future...
272 void
273 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
274                                  enum GNUNET_ATS_PreferenceKind kind,
275                                  float score)
276 {
277   // do nothing for now...
278 }
279
280
281 /**
282  * Initialize address subsystem.
283  *
284  * @param cfg configuration to use
285  */
286 void
287 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
288 {
289   GNUNET_assert (GNUNET_OK ==
290                  GNUNET_CONFIGURATION_get_value_number (cfg,
291                                                         "core",
292                                                         "TOTAL_QUOTA_IN",
293                                                         &total_quota_in));
294   GNUNET_assert (GNUNET_OK ==
295                  GNUNET_CONFIGURATION_get_value_number (cfg,
296                                                         "core",
297                                                         "TOTAL_QUOTA_OUT",
298                                                         &total_quota_out));
299   addresses = GNUNET_CONTAINER_multihashmap_create(128);
300 }
301
302
303 /**
304  * Free memory of address.
305  *
306  * @param cls NULL
307  * @param key peer identity (unused)
308  * @param value the 'struct ATS_Address' to free
309  * @return GNUNET_OK (continue to iterate)
310  */
311 static int 
312 free_address_it (void *cls,
313                  const GNUNET_HashCode * key,
314                  void *value)
315 {
316   struct ATS_Address * aa = value;
317
318   destroy_address (aa);
319   return GNUNET_OK;
320 }
321
322
323 void
324 GAS_addresses_destroy_all ()
325 {
326   if (addresses != NULL)
327     GNUNET_CONTAINER_multihashmap_iterate(addresses, 
328                                           &free_address_it, NULL);
329 }
330
331
332 /**
333  * Shutdown address subsystem.
334  */
335 void
336 GAS_addresses_done ()
337 {
338   GAS_addresses_destroy_all ();
339   GNUNET_CONTAINER_multihashmap_destroy (addresses);
340   addresses = NULL;
341 }
342
343
344 /* end of gnunet-service-ats_addresses.c */