use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2011-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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                                       addr->local_address_info,
74                                       GNUNET_BANDWIDTH_ZERO,
75                                       GNUNET_BANDWIDTH_ZERO);
76   GNUNET_free (addr->plugin);
77   GNUNET_free (addr);
78 }
79
80
81 /**
82  * Initialize @a norm.  Sets all historic values to undefined.
83  *
84  * @param norm normalization data to initialize
85  */
86 static void
87 init_norm (struct GAS_NormalizationInfo *norm)
88 {
89   unsigned int c;
90
91   for (c = 0; c < GAS_normalization_queue_length; c++)
92     norm->atsi_abs[c] = UINT64_MAX;
93 }
94
95
96 /**
97  * Create a ATS_address with the given information
98  *
99  * @param peer peer
100  * @param plugin_name plugin
101  * @param plugin_addr address
102  * @param plugin_addr_len address length
103  * @param local_address_info additional local info for the address
104  * @param session_id session identifier, can never be 0
105  * @return the ATS_Address
106  */
107 static struct ATS_Address *
108 create_address (const struct GNUNET_PeerIdentity *peer,
109                 const char *plugin_name,
110                 const void *plugin_addr,
111                 size_t plugin_addr_len,
112                 uint32_t local_address_info,
113                 uint32_t session_id)
114 {
115   struct ATS_Address *aa;
116
117   aa = GNUNET_malloc (sizeof(struct ATS_Address) + plugin_addr_len);
118   aa->peer = *peer;
119   aa->addr_len = plugin_addr_len;
120   aa->addr = &aa[1];
121   GNUNET_memcpy (&aa[1],
122                  plugin_addr,
123                  plugin_addr_len);
124   aa->plugin = GNUNET_strdup (plugin_name);
125   aa->session_id = session_id;
126   aa->local_address_info = local_address_info;
127   init_norm (&aa->norm_delay);
128   init_norm (&aa->norm_distance);
129   init_norm (&aa->norm_utilization_in);
130   init_norm (&aa->norm_utilization_out);
131   return aa;
132 }
133
134
135 /**
136  * Closure for #find_address_cb()
137  */
138 struct FindAddressContext
139 {
140   /**
141    * Session Id to look for.
142    */
143   uint32_t session_id;
144
145   /**
146    * Where to store matching address result.
147    */
148   struct ATS_Address *exact_address;
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   GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
228   new_address = create_address (peer,
229                                 plugin_name,
230                                 plugin_addr,
231                                 plugin_addr_len,
232                                 local_address_info,
233                                 session_id);
234   /* Add a new address */
235   new_address->properties = *prop;
236   new_address->t_added = GNUNET_TIME_absolute_get ();
237   new_address->t_last_activity = GNUNET_TIME_absolute_get ();
238   GNUNET_assert (GNUNET_OK ==
239                  GNUNET_CONTAINER_multipeermap_put (GSA_addresses,
240                                                     peer,
241                                                     new_address,
242                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
243   update_addresses_stat ();
244   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
245               "Adding new address for peer `%s' slot %u\n",
246               GNUNET_i2s (peer),
247               session_id);
248   /* Tell solver about new address */
249   GAS_plugin_solver_lock ();
250   GAS_plugin_new_address (new_address);
251   GAS_normalization_update_property (new_address);  // FIXME: needed?
252   GAS_plugin_solver_unlock ();
253   /* Notify performance clients about new address */
254   GAS_performance_notify_all_clients (&new_address->peer,
255                                       new_address->plugin,
256                                       new_address->addr,
257                                       new_address->addr_len,
258                                       new_address->active,
259                                       &new_address->properties,
260                                       new_address->local_address_info,
261                                       GNUNET_BANDWIDTH_value_init (
262                                         new_address->assigned_bw_out),
263                                       GNUNET_BANDWIDTH_value_init (
264                                         new_address->assigned_bw_in));
265 }
266
267
268 /**
269  * Update an address with new performance information for a peer.
270  *
271  * @param peer peer
272  * @param session_id session id, never 0
273  * @param prop performance information for this address
274  */
275 void
276 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
277                       uint32_t session_id,
278                       const struct GNUNET_ATS_Properties *prop)
279 {
280   struct ATS_Address *aa;
281
282   /* Get existing address */
283   aa = find_exact_address (peer,
284                            session_id);
285   if (NULL == aa)
286   {
287     GNUNET_break (0);
288     return;
289   }
290   if (NULL == aa->solver_information)
291   {
292     GNUNET_break (0);
293     return;
294   }
295   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
296               "Received ADDRESS_UPDATE for peer `%s' slot %u\n",
297               GNUNET_i2s (peer),
298               (unsigned int) session_id);
299   GNUNET_break (GNUNET_NT_UNSPECIFIED != prop->scope);
300   /* Update address */
301   aa->t_last_activity = GNUNET_TIME_absolute_get ();
302   aa->properties = *prop;
303   /* Notify performance clients about updated address */
304   GAS_performance_notify_all_clients (&aa->peer,
305                                       aa->plugin,
306                                       aa->addr,
307                                       aa->addr_len,
308                                       aa->active,
309                                       prop,
310                                       aa->local_address_info,
311                                       GNUNET_BANDWIDTH_value_init (
312                                         aa->assigned_bw_out),
313                                       GNUNET_BANDWIDTH_value_init (
314                                         aa->assigned_bw_in));
315
316   GAS_normalization_update_property (aa);
317 }
318
319
320 /**
321  * Remove an address for a peer.
322  *
323  * @param peer peer
324  * @param session_id session id, can never be 0
325  */
326 void
327 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
328                        uint32_t session_id)
329 {
330   struct ATS_Address *ea;
331
332   /* Get existing address */
333   ea = find_exact_address (peer,
334                            session_id);
335   if (NULL == ea)
336   {
337     GNUNET_break (0);
338     return;
339   }
340   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341               "Received ADDRESS_DESTROYED for peer `%s' session %u\n",
342               GNUNET_i2s (peer),
343               session_id);
344   free_address (ea);
345 }
346
347
348 /**
349  * Initialize address subsystem. The addresses subsystem manages the addresses
350  * known and current performance information. It has a solver component
351  * responsible for the resource allocation. It tells the solver about changes
352  * and receives updates when the solver changes the resource allocation.
353  */
354 void
355 GAS_addresses_init ()
356 {
357   GSA_addresses
358     = GNUNET_CONTAINER_multipeermap_create (128,
359                                             GNUNET_NO);
360   update_addresses_stat ();
361 }
362
363
364 /**
365  * Destroy all addresses iterator
366  *
367  * @param cls NULL
368  * @param key peer identity (unused)
369  * @param value the 'struct ATS_Address' to free
370  * @return #GNUNET_OK (continue to iterate)
371  */
372 static int
373 destroy_all_address_it (void *cls,
374                         const struct GNUNET_PeerIdentity *key,
375                         void *value)
376 {
377   struct ATS_Address *aa = value;
378
379   free_address (aa);
380   return GNUNET_OK;
381 }
382
383
384 /**
385  * Remove all addresses
386  */
387 void
388 GAS_addresses_destroy_all ()
389 {
390   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
391               "Destroying all addresses\n");
392   if (0 ==
393       GNUNET_CONTAINER_multipeermap_size (GSA_addresses))
394     return;
395   GAS_plugin_solver_lock ();
396   GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
397                                          &destroy_all_address_it,
398                                          NULL);
399   GAS_plugin_solver_unlock ();
400 }
401
402
403 /**
404  * Shutdown address subsystem.
405  */
406 void
407 GAS_addresses_done ()
408 {
409   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410               "Shutting down addresses\n");
411   GAS_plugin_solver_lock ();
412   GAS_addresses_destroy_all ();
413   GAS_plugin_solver_unlock ();
414   GNUNET_CONTAINER_multipeermap_destroy (GSA_addresses);
415   GSA_addresses = NULL;
416 }
417
418
419 /**
420  * Closure for #peerinfo_it().
421  */
422 struct PeerInfoIteratorContext
423 {
424   /**
425    * Function to call for each address.
426    */
427   GNUNET_ATS_PeerInfo_Iterator it;
428
429   /**
430    * Closure for @e it.
431    */
432   void *it_cls;
433 };
434
435
436 /**
437  * Iterator to iterate over a peer's addresses
438  *
439  * @param cls a `struct PeerInfoIteratorContext`
440  * @param key the peer id
441  * @param value the `struct ATS_address`
442  * @return #GNUNET_OK to continue
443  */
444 static int
445 peerinfo_it (void *cls,
446              const struct GNUNET_PeerIdentity *key,
447              void *value)
448 {
449   struct PeerInfoIteratorContext *pi_ctx = cls;
450   struct ATS_Address *addr = value;
451
452   pi_ctx->it (pi_ctx->it_cls,
453               &addr->peer,
454               addr->plugin,
455               addr->addr,
456               addr->addr_len,
457               addr->active,
458               &addr->properties,
459               addr->local_address_info,
460               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_out),
461               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_in));
462   return GNUNET_OK;
463 }
464
465
466 /**
467  * Return information all peers currently known to ATS
468  *
469  * @param peer the respective peer, NULL for 'all' peers
470  * @param pi_it the iterator to call for every peer
471  * @param pi_it_cls the closure for @a pi_it
472  */
473 void
474 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
475                              GNUNET_ATS_PeerInfo_Iterator pi_it,
476                              void *pi_it_cls)
477 {
478   struct PeerInfoIteratorContext pi_ctx;
479
480   if (NULL == pi_it)
481   {
482     /* does not make sense without callback */
483     GNUNET_break (0);
484     return;
485   }
486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487               "Returning information for %s from a total of %u known addresses\n",
488               (NULL == peer)
489               ? "all peers"
490               : GNUNET_i2s (peer),
491               (unsigned int) GNUNET_CONTAINER_multipeermap_size (
492                 GSA_addresses));
493   pi_ctx.it = pi_it;
494   pi_ctx.it_cls = pi_it_cls;
495   if (NULL == peer)
496     GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
497                                            &peerinfo_it,
498                                            &pi_ctx);
499   else
500     GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
501                                                 peer,
502                                                 &peerinfo_it, &pi_ctx);
503   pi_it (pi_it_cls,
504          NULL, NULL, NULL, 0,
505          GNUNET_NO,
506          NULL,
507          GNUNET_HELLO_ADDRESS_INFO_NONE,
508          GNUNET_BANDWIDTH_ZERO,
509          GNUNET_BANDWIDTH_ZERO);
510 }
511
512
513 /**
514  * Information we need for the callbacks to return a list of addresses
515  * back to the client.
516  */
517 struct AddressIteration
518 {
519   /**
520    * Actual handle to the client.
521    */
522   struct GNUNET_SERVICE_Client *client;
523
524   /**
525    * Are we sending all addresses, or only those that are active?
526    */
527   int all;
528
529   /**
530    * Which ID should be included in the response?
531    */
532   uint32_t id;
533 };
534
535
536 /**
537  * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
538  * given address details to the client identified in @a ai.
539  *
540  * @param ai our address information context (identifies the client)
541  * @param id the peer id this address is for
542  * @param plugin_name name of the plugin that supports this address
543  * @param plugin_addr address
544  * @param plugin_addr_len length of @a plugin_addr
545  * @param active #GNUNET_YES if this address is actively used
546  * @param prop performance information
547  * @param local_address_info flags for the address
548  * @param bandwidth_out current outbound bandwidth assigned to address
549  * @param bandwidth_in current inbound bandwidth assigned to address
550  */
551 static void
552 transmit_req_addr (struct AddressIteration *ai,
553                    const struct GNUNET_PeerIdentity *id,
554                    const char *plugin_name,
555                    const void *plugin_addr,
556                    size_t plugin_addr_len,
557                    int active,
558                    const struct GNUNET_ATS_Properties *prop,
559                    enum GNUNET_HELLO_AddressInfo local_address_info,
560                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
561                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
562
563 {
564   struct GNUNET_MQ_Envelope *env;
565   struct PeerInformationMessage *msg;
566   char *addrp;
567   size_t plugin_name_length;
568   size_t msize;
569
570   if (NULL != plugin_name)
571     plugin_name_length = strlen (plugin_name) + 1;
572   else
573     plugin_name_length = 0;
574   msize = plugin_addr_len + plugin_name_length;
575
576   GNUNET_assert (sizeof(struct PeerInformationMessage) + msize
577                  < GNUNET_MAX_MESSAGE_SIZE);
578   env = GNUNET_MQ_msg_extra (msg,
579                              msize,
580                              GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
581   msg->id = htonl (ai->id);
582   if (NULL != id)
583     msg->peer = *id;
584   msg->address_length = htons (plugin_addr_len);
585   msg->address_active = ntohl (active);
586   msg->plugin_name_length = htons (plugin_name_length);
587   msg->bandwidth_out = bandwidth_out;
588   msg->bandwidth_in = bandwidth_in;
589   if (NULL != prop)
590     GNUNET_ATS_properties_hton (&msg->properties,
591                                 prop);
592   msg->address_local_info = htonl ((uint32_t) local_address_info);
593   addrp = (char *) &msg[1];
594   GNUNET_memcpy (addrp,
595                  plugin_addr,
596                  plugin_addr_len);
597   if (NULL != plugin_name)
598     strcpy (&addrp[plugin_addr_len],
599             plugin_name);
600   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (ai->client),
601                   env);
602 }
603
604
605 /**
606  * Iterator for #GAS_addresses_get_peer_info(), called with peer-specific
607  * information to be passed back to the client.
608  *
609  * @param cls closure with our `struct AddressIteration *`
610  * @param id the peer id
611  * @param plugin_name plugin name
612  * @param plugin_addr address
613  * @param plugin_addr_len length of @a plugin_addr
614  * @param active is address actively used
615  * @param prop performance information
616  * @param local_address_info additional local info for the address
617  * @param bandwidth_out current outbound bandwidth assigned to address
618  * @param bandwidth_in current inbound bandwidth assigned to address
619  */
620 static void
621 req_addr_peerinfo_it (void *cls,
622                       const struct GNUNET_PeerIdentity *id,
623                       const char *plugin_name,
624                       const void *plugin_addr,
625                       size_t plugin_addr_len,
626                       int active,
627                       const struct GNUNET_ATS_Properties *prop,
628                       enum GNUNET_HELLO_AddressInfo local_address_info,
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                      local_address_info,
661                      bandwidth_out,
662                      bandwidth_in);
663 }
664
665
666 /**
667  * Handle 'address list request' messages from clients.
668  *
669  * @param cls client that sent the request
670  * @param alrm the request message
671  */
672 void
673 GAS_handle_request_address_list (struct GNUNET_SERVICE_Client *client,
674                                  const struct AddressListRequestMessage *alrm)
675 {
676   struct AddressIteration ai;
677   struct GNUNET_PeerIdentity allzeros;
678
679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680               "Received ADDRESSLIST_REQUEST message\n");
681   ai.all = ntohl (alrm->all);
682   ai.id = ntohl (alrm->id);
683   ai.client = client;
684
685   memset (&allzeros,
686           '\0',
687           sizeof(struct GNUNET_PeerIdentity));
688   if (0 == GNUNET_is_zero (&alrm->peer))
689   {
690     /* Return addresses for all peers */
691     GAS_addresses_get_peer_info (NULL,
692                                  &req_addr_peerinfo_it,
693                                  &ai);
694   }
695   else
696   {
697     /* Return addresses for a specific peer */
698     GAS_addresses_get_peer_info (&alrm->peer,
699                                  &req_addr_peerinfo_it,
700                                  &ai);
701   }
702   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
703               "Finished handling `%s' message\n",
704               "ADDRESSLIST_REQUEST");
705   transmit_req_addr (&ai,
706                      NULL, NULL, NULL,
707                      0, GNUNET_NO,
708                      NULL,
709                      GNUNET_HELLO_ADDRESS_INFO_NONE,
710                      GNUNET_BANDWIDTH_ZERO,
711                      GNUNET_BANDWIDTH_ZERO);
712 }
713
714
715 /* end of gnunet-service-ats_addresses.c */