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