fix use-after-free on exit
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2015 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_normalization.h"
31 #include "gnunet-service-ats_plugins.h"
32
33
34 /**
35  * A multihashmap to store all addresses
36  */
37 struct GNUNET_CONTAINER_MultiPeerMap *GSA_addresses;
38
39
40 /**
41  * Update statistic on number of addresses.
42  */
43 static void
44 update_addresses_stat ()
45 {
46   GNUNET_STATISTICS_set (GSA_stats,
47                          "# addresses",
48                          GNUNET_CONTAINER_multipeermap_size (GSA_addresses),
49                          GNUNET_NO);
50 }
51
52
53 /**
54  * Free the given address
55  *
56  * @param addr address to destroy
57  */
58 static void
59 free_address (struct ATS_Address *addr)
60 {
61   GNUNET_assert (GNUNET_YES ==
62                  GNUNET_CONTAINER_multipeermap_remove (GSA_addresses,
63                                                        &addr->peer,
64                                                        addr));
65   update_addresses_stat ();
66   GAS_plugin_delete_address (addr);
67   GAS_performance_notify_all_clients (&addr->peer,
68                                       addr->plugin,
69                                       addr->addr,
70                                       addr->addr_len,
71                                       GNUNET_NO,
72                                       NULL,
73                                       GNUNET_BANDWIDTH_ZERO,
74                                       GNUNET_BANDWIDTH_ZERO);
75   GNUNET_free (addr->plugin);
76   GNUNET_free (addr);
77 }
78
79
80 /**
81  * Initialize @a norm.  Sets all historic values to undefined.
82  *
83  * @param norm normalization data to initialize
84  */
85 static void
86 init_norm (struct GAS_NormalizationInfo *norm)
87 {
88   unsigned int c;
89
90   for (c = 0; c < GAS_normalization_queue_length; c++)
91     norm->atsi_abs[c] = UINT64_MAX;
92 }
93
94
95 /**
96  * Create a ATS_address with the given information
97  *
98  * @param peer peer
99  * @param plugin_name plugin
100  * @param plugin_addr address
101  * @param plugin_addr_len address length
102  * @param local_address_info additional local info for the address
103  * @param session_id session identifier, can never be 0
104  * @return the ATS_Address
105  */
106 static struct ATS_Address *
107 create_address (const struct GNUNET_PeerIdentity *peer,
108                 const char *plugin_name,
109                 const void *plugin_addr,
110                 size_t plugin_addr_len,
111                 uint32_t local_address_info,
112                 uint32_t session_id)
113 {
114   struct ATS_Address *aa;
115
116   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
117   aa->peer = *peer;
118   aa->addr_len = plugin_addr_len;
119   aa->addr = &aa[1];
120   memcpy (&aa[1],
121           plugin_addr,
122           plugin_addr_len);
123   aa->plugin = GNUNET_strdup (plugin_name);
124   aa->session_id = session_id;
125   aa->local_address_info = local_address_info;
126   init_norm (&aa->norm_delay);
127   init_norm (&aa->norm_distance);
128   init_norm (&aa->norm_utilization_in);
129   init_norm (&aa->norm_utilization_out);
130   return aa;
131 }
132
133
134 /**
135  * Closure for #find_address_cb()
136  */
137 struct FindAddressContext
138 {
139   /**
140    * Session Id to look for.
141    */
142   uint32_t session_id;
143
144   /**
145    * Where to store matching address result.
146    */
147   struct ATS_Address *exact_address;
148
149 };
150
151
152 /**
153  * Find session matching given session ID.
154  *
155  * @param cls a `struct FindAddressContext`
156  * @param key peer id
157  * @param value the address to compare with
158  * @return #GNUNET_YES to continue, #GNUNET_NO if address is found
159  */
160 static int
161 find_address_cb (void *cls,
162                  const struct GNUNET_PeerIdentity *key,
163                  void *value)
164 {
165   struct FindAddressContext *fac = cls;
166   struct ATS_Address *aa = value;
167
168   if (aa->session_id == fac->session_id)
169   {
170     fac->exact_address = aa;
171     return GNUNET_NO;
172   }
173   return GNUNET_YES;
174 }
175
176
177 /**
178  * Find the exact address
179  *
180  * @param peer peer
181  * @param session_id session id, can never be 0
182  * @return an ATS_address or NULL
183  */
184 static struct ATS_Address *
185 find_exact_address (const struct GNUNET_PeerIdentity *peer,
186                     uint32_t session_id)
187 {
188   struct FindAddressContext fac;
189
190   fac.exact_address = NULL;
191   fac.session_id = session_id;
192   GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
193                                               peer,
194                                               &find_address_cb, &fac);
195   return fac.exact_address;
196 }
197
198
199 /**
200  * Add a new address for a peer.
201  *
202  * @param peer peer
203  * @param plugin_name transport plugin name
204  * @param plugin_addr plugin address
205  * @param plugin_addr_len length of the plugin address in @a plugin_addr
206  * @param local_address_info the local address for the address
207  * @param session_id session id, can be 0
208  * @param prop performance information for this address
209  */
210 void
211 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
212                    const char *plugin_name,
213                    const void *plugin_addr,
214                    size_t plugin_addr_len,
215                    uint32_t local_address_info,
216                    uint32_t session_id,
217                    const struct GNUNET_ATS_Properties *prop)
218 {
219   struct ATS_Address *new_address;
220
221   if (NULL != find_exact_address (peer,
222                                   session_id))
223   {
224     GNUNET_break (0);
225     return;
226   }
227   new_address = create_address (peer,
228                                 plugin_name,
229                                 plugin_addr,
230                                 plugin_addr_len,
231                                 local_address_info,
232                                 session_id);
233   /* Add a new address */
234   new_address->properties = *prop;
235   new_address->t_added = GNUNET_TIME_absolute_get();
236   new_address->t_last_activity = GNUNET_TIME_absolute_get();
237   GNUNET_assert(GNUNET_OK ==
238                 GNUNET_CONTAINER_multipeermap_put (GSA_addresses,
239                                                    peer,
240                                                    new_address,
241                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
242   update_addresses_stat ();
243   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244               "Adding new address for peer `%s' slot %u\n",
245               GNUNET_i2s (peer),
246               session_id);
247   /* Tell solver about new address */
248   GAS_plugin_solver_lock ();
249   GAS_plugin_new_address (new_address);
250   GAS_normalization_update_property (new_address); // FIXME: needed?
251   GAS_plugin_solver_unlock ();
252   /* Notify performance clients about new address */
253   GAS_performance_notify_all_clients (&new_address->peer,
254                                       new_address->plugin,
255                                       new_address->addr,
256                                       new_address->addr_len,
257                                       new_address->active,
258                                       &new_address->properties,
259                                       GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_out),
260                                       GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_in));
261 }
262
263
264 /**
265  * Update an address with new performance information for a peer.
266  *
267  * @param peer peer
268  * @param session_id session id, never 0
269  * @param prop performance information for this address
270  */
271 void
272 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
273                       uint32_t session_id,
274                       const struct GNUNET_ATS_Properties *prop)
275 {
276   struct ATS_Address *aa;
277
278   /* Get existing address */
279   aa = find_exact_address (peer,
280                            session_id);
281   if (NULL == aa)
282   {
283     GNUNET_break (0);
284     return;
285   }
286   if (NULL == aa->solver_information)
287   {
288     GNUNET_break (0);
289     return;
290   }
291   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292               "Received ADDRESS_UPDATE for peer `%s' slot %u\n",
293               GNUNET_i2s (peer),
294               (unsigned int) session_id);
295
296   /* Update address */
297   aa->t_last_activity = GNUNET_TIME_absolute_get();
298   aa->properties = *prop;
299   /* Notify performance clients about updated address */
300   GAS_performance_notify_all_clients (&aa->peer,
301                                       aa->plugin,
302                                       aa->addr,
303                                       aa->addr_len,
304                                       aa->active,
305                                       prop,
306                                       GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
307                                       GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
308
309   GAS_normalization_update_property (aa);
310 }
311
312
313 /**
314  * Remove an address for a peer.
315  *
316  * @param peer peer
317  * @param session_id session id, can never be 0
318  */
319 void
320 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
321                        uint32_t session_id)
322 {
323   struct ATS_Address *ea;
324
325   /* Get existing address */
326   ea = find_exact_address (peer,
327                            session_id);
328   if (NULL == ea)
329   {
330     GNUNET_break (0);
331     return;
332   }
333   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334               "Received ADDRESS_DESTROYED for peer `%s' session %u\n",
335               GNUNET_i2s (peer),
336               session_id);
337   free_address (ea);
338 }
339
340
341 /**
342  * Initialize address subsystem. The addresses subsystem manages the addresses
343  * known and current performance information. It has a solver component
344  * responsible for the resource allocation. It tells the solver about changes
345  * and receives updates when the solver changes the resource allocation.
346  *
347  * @param server handle to our server
348  */
349 void
350 GAS_addresses_init (struct GNUNET_SERVER_Handle *server)
351 {
352   GSA_addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
353   update_addresses_stat ();
354 }
355
356
357 /**
358  * Destroy all addresses iterator
359  *
360  * @param cls NULL
361  * @param key peer identity (unused)
362  * @param value the 'struct ATS_Address' to free
363  * @return #GNUNET_OK (continue to iterate)
364  */
365 static int
366 destroy_all_address_it (void *cls,
367                         const struct GNUNET_PeerIdentity *key,
368                         void *value)
369 {
370   struct ATS_Address *aa = value;
371
372   free_address (aa);
373   return GNUNET_OK;
374 }
375
376
377 /**
378  * Remove all addresses
379  */
380 void
381 GAS_addresses_destroy_all ()
382 {
383   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
384               "Destroying all addresses\n");
385   if (0 ==
386       GNUNET_CONTAINER_multipeermap_size (GSA_addresses))
387     return;
388   GAS_plugin_solver_lock ();
389   GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
390                                          &destroy_all_address_it,
391                                          NULL);
392   GAS_plugin_solver_unlock ();
393 }
394
395
396 /**
397  * Shutdown address subsystem.
398  */
399 void
400 GAS_addresses_done ()
401 {
402   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
403              "Shutting down addresses\n");
404   GAS_addresses_destroy_all ();
405   GNUNET_CONTAINER_multipeermap_destroy (GSA_addresses);
406   GSA_addresses = NULL;
407 }
408
409
410 /**
411  * Closure for #peerinfo_it().
412  */
413 struct PeerInfoIteratorContext
414 {
415   /**
416    * Function to call for each address.
417    */
418   GNUNET_ATS_PeerInfo_Iterator it;
419
420   /**
421    * Closure for @e it.
422    */
423   void *it_cls;
424 };
425
426
427 /**
428  * Iterator to iterate over a peer's addresses
429  *
430  * @param cls a `struct PeerInfoIteratorContext`
431  * @param key the peer id
432  * @param value the `struct ATS_address`
433  * @return #GNUNET_OK to continue
434  */
435 static int
436 peerinfo_it (void *cls,
437              const struct GNUNET_PeerIdentity *key,
438              void *value)
439 {
440   struct PeerInfoIteratorContext *pi_ctx = cls;
441   struct ATS_Address *addr = value;
442
443   pi_ctx->it (pi_ctx->it_cls,
444               &addr->peer,
445               addr->plugin,
446               addr->addr,
447               addr->addr_len,
448               addr->active,
449               &addr->properties,
450               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_out),
451               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_in));
452   return GNUNET_OK;
453 }
454
455
456 /**
457  * Return information all peers currently known to ATS
458  *
459  * @param peer the respective peer, NULL for 'all' peers
460  * @param pi_it the iterator to call for every peer
461  * @param pi_it_cls the closure for @a pi_it
462  */
463 void
464 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
465                              GNUNET_ATS_PeerInfo_Iterator pi_it,
466                              void *pi_it_cls)
467 {
468   struct PeerInfoIteratorContext pi_ctx;
469
470   if (NULL == pi_it)
471   {
472     /* does not make sense without callback */
473     GNUNET_break (0);
474     return;
475   }
476   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
477               "Returning information for %s from a total of %u known addresses\n",
478               (NULL == peer)
479               ? "all peers"
480               : GNUNET_i2s (peer),
481               (unsigned int) GNUNET_CONTAINER_multipeermap_size (GSA_addresses));
482   pi_ctx.it = pi_it;
483   pi_ctx.it_cls = pi_it_cls;
484   if (NULL == peer)
485     GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
486                                            &peerinfo_it,
487                                            &pi_ctx);
488   else
489     GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
490                                                 peer,
491                                                 &peerinfo_it, &pi_ctx);
492   pi_it (pi_it_cls,
493          NULL, NULL, NULL, 0,
494          GNUNET_NO,
495          NULL,
496          GNUNET_BANDWIDTH_ZERO,
497          GNUNET_BANDWIDTH_ZERO);
498 }
499
500
501 /**
502  * Information we need for the callbacks to return a list of addresses
503  * back to the client.
504  */
505 struct AddressIteration
506 {
507   /**
508    * Actual handle to the client.
509    */
510   struct GNUNET_SERVER_Client *client;
511
512   /**
513    * Are we sending all addresses, or only those that are active?
514    */
515   int all;
516
517   /**
518    * Which ID should be included in the response?
519    */
520   uint32_t id;
521
522 };
523
524
525 /**
526  * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
527  * given address details to the client identified in @a ai.
528  *
529  * @param ai our address information context (identifies the client)
530  * @param id the peer id this address is for
531  * @param plugin_name name of the plugin that supports this address
532  * @param plugin_addr address
533  * @param plugin_addr_len length of @a plugin_addr
534  * @param active #GNUNET_YES if this address is actively used
535  * @param prop performance information
536  * @param bandwidth_out current outbound bandwidth assigned to address
537  * @param bandwidth_in current inbound bandwidth assigned to address
538  */
539 static void
540 transmit_req_addr (struct AddressIteration *ai,
541                    const struct GNUNET_PeerIdentity *id,
542                    const char *plugin_name,
543                    const void *plugin_addr,
544                    size_t plugin_addr_len,
545                    int active,
546                    const struct GNUNET_ATS_Properties *prop,
547                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
548                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
549
550 {
551   struct PeerInformationMessage *msg;
552   char *addrp;
553   size_t plugin_name_length;
554   size_t msize;
555   struct GNUNET_SERVER_NotificationContext **uc;
556   struct GNUNET_SERVER_NotificationContext *nc;
557
558   if (NULL != plugin_name)
559     plugin_name_length = strlen (plugin_name) + 1;
560   else
561     plugin_name_length = 0;
562   msize = sizeof (struct PeerInformationMessage) +
563           plugin_addr_len + plugin_name_length;
564   char buf[msize] GNUNET_ALIGN;
565
566   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
567   msg = (struct PeerInformationMessage *) buf;
568   msg->header.size = htons (msize);
569   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
570   msg->id = htonl (ai->id);
571   if (NULL != id)
572     msg->peer = *id;
573   else
574     memset (&msg->peer, '\0', sizeof (struct GNUNET_PeerIdentity));
575   msg->address_length = htons (plugin_addr_len);
576   msg->address_active = ntohl (active);
577   msg->plugin_name_length = htons (plugin_name_length);
578   msg->bandwidth_out = bandwidth_out;
579   msg->bandwidth_in = bandwidth_in;
580   if (NULL != prop)
581     GNUNET_ATS_properties_hton (&msg->properties,
582                                 prop);
583   else
584     memset (&msg->properties,
585             0,
586             sizeof (struct GNUNET_ATS_Properties));
587   addrp = (char *) &msg[1];
588   if (NULL != plugin_addr)
589     memcpy (addrp, plugin_addr, plugin_addr_len);
590   if (NULL != plugin_name)
591     strcpy (&addrp[plugin_addr_len], plugin_name);
592   uc = GNUNET_SERVER_client_get_user_context (ai->client,
593                                               struct GNUNET_SERVER_NotificationContext *);
594   if (NULL == uc)
595   {
596     GNUNET_break (0);
597     return;
598   }
599   nc = *uc;
600   GNUNET_SERVER_notification_context_unicast (nc,
601                                               ai->client,
602                                               &msg->header,
603                                               GNUNET_NO);
604 }
605
606
607 /**
608  * Iterator for #GAS_addresses_get_peer_info(), called with peer-specific
609  * information to be passed back to the client.
610  *
611  * @param cls closure with our `struct AddressIteration *`
612  * @param id the peer id
613  * @param plugin_name plugin name
614  * @param plugin_addr address
615  * @param plugin_addr_len length of @a plugin_addr
616  * @param active is address actively used
617  * @param prop performance information
618  * @param bandwidth_out current outbound bandwidth assigned to address
619  * @param bandwidth_in current inbound bandwidth assigned to address
620  */
621 static void
622 req_addr_peerinfo_it (void *cls,
623                       const struct GNUNET_PeerIdentity *id,
624                       const char *plugin_name,
625                       const void *plugin_addr,
626                       size_t plugin_addr_len,
627                       int active,
628                       const struct GNUNET_ATS_Properties *prop,
629                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
630                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
631 {
632   struct AddressIteration *ai = cls;
633
634   if ( (NULL == id) &&
635        (NULL == plugin_name) &&
636        (NULL == plugin_addr) )
637   {
638     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639                 "Address iteration done for one peer\n");
640     return;
641   }
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643               "Callback for %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
644               (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
645               GNUNET_i2s (id),
646               plugin_name,
647               (unsigned int) ntohl (bandwidth_out.value__),
648               (unsigned int) ntohl (bandwidth_in.value__));
649   /* Transmit result (either if address is active, or if
650      client wanted all addresses) */
651   if ( (GNUNET_YES != ai->all) &&
652        (GNUNET_YES != active))
653     return;
654   transmit_req_addr (ai,
655                      id,
656                      plugin_name,
657                      plugin_addr, plugin_addr_len,
658                      active,
659                      prop,
660                      bandwidth_out,
661                      bandwidth_in);
662 }
663
664
665 /**
666  * Handle 'address list request' messages from clients.
667  *
668  * @param cls unused, NULL
669  * @param client client that sent the request
670  * @param message the request message
671  */
672 void
673 GAS_handle_request_address_list (void *cls,
674                                  struct GNUNET_SERVER_Client *client,
675                                  const struct GNUNET_MessageHeader *message)
676 {
677   struct AddressIteration ai;
678   const struct AddressListRequestMessage *alrm;
679   struct GNUNET_PeerIdentity allzeros;
680
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "Received ADDRESSLIST_REQUEST message\n");
683   alrm = (const struct AddressListRequestMessage *) message;
684   ai.all = ntohl (alrm->all);
685   ai.id = ntohl (alrm->id);
686   ai.client = client;
687
688   memset (&allzeros,
689           '\0',
690           sizeof (struct GNUNET_PeerIdentity));
691   if (0 == memcmp (&alrm->peer,
692                    &allzeros,
693                    sizeof (struct GNUNET_PeerIdentity)))
694   {
695     /* Return addresses for all peers */
696     GAS_addresses_get_peer_info (NULL,
697                                  &req_addr_peerinfo_it,
698                                  &ai);
699   }
700   else
701   {
702     /* Return addresses for a specific peer */
703     GAS_addresses_get_peer_info (&alrm->peer,
704                                  &req_addr_peerinfo_it,
705                                  &ai);
706   }
707   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708               "Finished handling `%s' message\n",
709               "ADDRESSLIST_REQUEST");
710   transmit_req_addr (&ai,
711                      NULL, NULL, NULL,
712                      0, GNUNET_NO,
713                      NULL,
714                      GNUNET_BANDWIDTH_ZERO,
715                      GNUNET_BANDWIDTH_ZERO);
716   GNUNET_SERVER_receive_done (client,
717                               GNUNET_OK);
718 }
719
720
721
722 /* end of gnunet-service-ats_addresses.c */