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