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