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